128 'Company Confidential');
231 public $lastretval =
'';
232 private $_errorsTo =
'';
233 private $_deliveryReceipt = 0;
234 private $_trackId =
'';
235 private $_moreinheader =
'';
261 $this->_deliveryReceipt = $_val;
271 return $this->_deliveryReceipt;
282 $this->_trackId = $_val;
293 $this->_moreinheader = $_val;
303 return $this->_trackId;
313 return $this->_moreinheader;
339 if ($_part ===
true) {
340 $_retValue = $this->_errorsTo;
342 $_retValue = $this->_errorsTo[$_part];
356 $this->_debug = $_vDebug;
367 $_aryToList = $this->getTO();
386 $usetls = preg_match(
'@tls://@i', $host);
388 $host = preg_replace(
'@tcp://@i',
'', $host);
389 $host = preg_replace(
'@ssl://@i',
'', $host);
390 $host = preg_replace(
'@tls://@i',
'', $host);
393 include_once DOL_DOCUMENT_ROOT.
'/core/lib/functions2.lib.php';
395 if ((!
is_ip($host)) && ((gethostbyname($host)) == $host)) {
396 $this->
_setErr(99, $host.
' is either offline or is an invalid host name.');
399 if (function_exists(
'stream_socket_client') && !empty($this->_options)) {
400 $socket_context = stream_context_create($this->_options);
401 $this->socket = @stream_socket_client(
402 preg_replace(
'@tls://@i',
'', $this->
getHost()).
407 STREAM_CLIENT_CONNECT,
411 $this->socket = @fsockopen(
412 preg_replace(
'@tls://@i',
'', $this->
getHost()),
421 if (is_resource($this->socket)) {
426 if (function_exists(
'stream_set_timeout')) {
427 stream_set_timeout($this->socket, $this->_smtpTimeout, 0);
431 if ($_retVal = $this->
server_parse($this->socket,
"220")) {
432 $_retVal = $this->socket;
437 if (empty($this->errstr)) {
438 $this->errstr =
'Failed to connect with fsockopen host='.$this->getHost().
' port='.$this->
getPort();
440 $this->
_setErr($this->errno, $this->errstr);
463 $usetls = preg_match(
'@tls://@i', $host);
465 $host = preg_replace(
'@tcp://@i',
'', $host);
466 $host = preg_replace(
'@ssl://@i',
'', $host);
467 $host = preg_replace(
'@tls://@i',
'', $host);
469 if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
470 $host =
'tls://'.$host;
475 if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
476 if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
478 $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
482 $hosth = $this->
getFrom(
'addr');
483 $hosth = preg_replace(
'/^.*</',
'', $hosth);
484 $hosth = preg_replace(
'/>.*$/',
'', $hosth);
485 $hosth = preg_replace(
'/.*@/',
'', $hosth);
544 $this->
_setErr(131,
'STARTTLS connection is not supported.');
555 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
556 if (defined(
'STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
557 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
558 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
561 if (!stream_socket_enable_crypto($this->socket,
true, $crypto_method)) {
562 $this->
_setErr(132,
'STARTTLS connection failed.');
568 $this->
_setErr(126,
'"'.$hosth.
'" does not support authenticated connections or temporary error. Error after 2nd sending EHLO '.$hosth.
' : '.$this->lastretval);
574 if (empty($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE)) {
575 $conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE =
'LOGIN';
580 switch ($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE) {
588 $_retVal = $this->
socket_send_str(base64_encode(
"\0".$this->_smtpsID.
"\0".$this->_smtpsPW),
'235');
594 $initRes =
"user=".$user.
"\001auth=Bearer ".$token.
"\001\001";
595 $_retVal = $this->
socket_send_str(
'AUTH XOAUTH2 '.base64_encode($initRes),
'235');
597 $this->
_setErr(130,
'Error when asking for AUTH XOAUTH2');
604 $this->
_setErr(130,
'Error when asking for AUTH LOGIN');
610 $_retVal = $this->
socket_send_str(base64_encode($this->_smtpsPW),
'235');
615 $this->
_setErr(130,
'Invalid Authentication Credentials.');
618 $this->
_setErr(126,
'"'.$host.
'" does not support authenticated connections or temporary error. Error after sending EHLO '.$hosth.
' : '.$this->lastretval);
641 if (!empty($this->_smtpsID) && (!empty($this->_smtpsPW) || !empty($this->_smtpsToken))) {
648 $usetls = preg_match(
'@tls://@i', $host);
650 $host = preg_replace(
'@tcp://@i',
'', $host);
651 $host = preg_replace(
'@ssl://@i',
'', $host);
652 $host = preg_replace(
'@tls://@i',
'', $host);
654 if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
655 $host =
'tls://'.$host;
660 if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
661 if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
663 $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
667 $hosth = $this->
getFrom(
'addr');
668 $hosth = preg_replace(
'/^.*</',
'', $hosth);
669 $hosth = preg_replace(
'/>.*$/',
'', $hosth);
670 $hosth = preg_replace(
'/.*@/',
'', $hosth);
684 if (!$resultmailfrom) {
685 fclose($this->socket);
720 fputs($this->socket,
'QUIT');
725 fclose($this->socket);
770 if (!empty($_strConfigPath)) {
773 if (!@include $_strConfigPath) {
774 $this->
_setErr(110,
'"'.$_strConfigPath.
'" is not a valid path.');
781 if ($_host = ini_get(
'SMTPs')) {
785 if ($_port = ini_get(
'smtp_port')) {
789 if ($_from = ini_get(
'sendmail_from')) {
809 if ((is_numeric($_type)) && (($_type >= 0) && ($_type <= 3))) {
810 $this->_transportType = $_type;
853 $this->_smtpsHost = $_strHost;
878 if ((is_numeric($_intPort)) &&
879 (($_intPort >= 1) && ($_intPort <= 65536))) {
880 $this->_smtpsPort = $_intPort;
903 $this->_smtpsID = $_strID;
924 $this->_smtpsPW = $_strPW;
945 $this->_smtpsToken = $_strToken;
968 $this->_smtpsCharSet = $_strCharSet;
999 if (array_search($_strTransEncode, $this->_smtpsTransEncodeTypes)) {
1000 $this->_smtpsTransEncode = $_strTransEncode;
1032 if (array_search($_strTransEncodeType, $this->_smtpsTransEncodeTypes)) {
1033 $this->_smtpsTransEncodeType = $_strTransEncodeType;
1073 if ($_part ===
true) {
1076 $_retValue = $this->_msgFrom[$_part];
1091 $this->_msgReplyTo = $this->
_strip_email($_strReplyTo);
1105 if ($_part ===
true) {
1108 $_retValue = $this->_msgReplyTo[$_part];
1132 if (!empty($_addrList)) {
1134 if (is_string($_addrList)) {
1136 if (strstr($_addrList,
',')) {
1138 $_addrList = explode(
',', $_addrList);
1141 $_addrList = array($_addrList);
1146 foreach ($_addrList as $_strAddr) {
1148 $_strAddr = str_replace(
'>',
'', $_strAddr);
1152 $_tmpaddr = explode(
'<', $_strAddr);
1155 if (count($_tmpaddr) == 2) {
1156 $_tmpHost = explode(
'@', $_tmpaddr[1]);
1157 $_tmpaddr[0] = trim($_tmpaddr[0],
' ">');
1158 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = $_tmpaddr[0];
1162 $_strAddr = str_replace(
'<',
'', $_strAddr);
1164 $_tmpHost = explode(
'@', $_strAddr);
1165 $_tmpHost[0] = trim($_tmpHost[0]);
1166 $_tmpHost[1] = trim($_tmpHost[1]);
1168 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] =
'';
1173 $this->_msgRecipients = $aryHost;
1197 $_aryEmail[
'org'] = $_strAddr;
1200 $_strAddr = strtolower($_strAddr);
1203 $_strAddr = trim($_strAddr,
' ">');
1206 $_tmpAry = explode(
'<', $_strAddr);
1209 if (count($_tmpAry) == 2) {
1212 $_aryEmail[
'real'] = trim($_tmpAry[0],
' ">');
1215 $_aryEmail[
'addr'] = $_tmpAry[1];
1217 $_aryEmail[
'addr'] = $_tmpAry[0];
1221 list($_aryEmail[
'user'], $_aryEmail[
'host']) = explode(
'@', $_aryEmail[
'addr']);
1224 $_aryEmail[
'addr'] =
'<'.$_aryEmail[
'addr'].
'>';
1243 $_RCPT_list = array();
1246 foreach ($this->_msgRecipients as $_host => $_list) {
1247 foreach ($_list as $_subList) {
1248 foreach ($_subList as $_name => $_addr) {
1250 $_RCPT_list[] = $_name.
'@'.$_host;
1271 if ($this->_msgRecipients) {
1272 $_RCPT_list = array();
1274 foreach ($this->_msgRecipients as $_host => $_list) {
1275 if (!empty($this->_msgRecipients[$_host][$_which])) {
1276 foreach ($this->_msgRecipients[$_host][$_which] as $_addr => $_realName) {
1278 $_realName =
'"'.$_realName.
'"';
1279 $_RCPT_list[] = $_realName.
' <'.$_addr.
'@'.$_host.
'>';
1281 $_RCPT_list[] = $_addr.
'@'.$_host;
1287 return implode(
', ', $_RCPT_list);
1289 $this->
_setErr(101,
'No eMail Address for message to be sent to.');
1293 $this->
_setErr(102,
'eMail type not defined.');
1376 $this->_msgSubject = $_strSubject;
1399 $_header =
'From: '.$this->getFrom(
'org').
"\r\n"
1400 .
'To: '.$this->getTO().
"\r\n";
1402 if ($this->
getCC()) {
1403 $_header .=
'Cc: '.$this->getCC().
"\r\n";
1417 $host = dol_getprefix(
'email');
1420 $_header .=
'Subject: '.$this->getSubject().
"\r\n";
1421 $_header .=
'Date: '.date(
"r").
"\r\n";
1426 $_header .=
'Message-ID: <'.time().
'.SMTPs-dolibarr-'.$trackid.
'@'.$host.
">\r\n";
1427 $_header .=
'References: <'.time().
'.SMTPs-dolibarr-'.$trackid.
'@'.$host.
">\r\n";
1428 $_header .=
'X-Dolibarr-TRACKID: '.$trackid.
'@'.$host.
"\r\n";
1430 $_header .=
'Message-ID: <'.time().
'.SMTPs@'.$host.
">\r\n";
1432 if (!empty($_SERVER[
'REMOTE_ADDR'])) {
1433 $_header .=
"X-RemoteAddr: ".$_SERVER[
'REMOTE_ADDR'].
"\r\n";
1444 $_header .=
'Sensitivity: '.$this->getSensitivity().
"\r\n";
1447 if ($this->_msgPriority != 3) {
1454 $_header .=
'Disposition-Notification-To: '.$this->getFrom(
'addr').
"\r\n";
1457 $_header .=
'Errors-To: '.$this->getErrorsTo(
'addr').
"\r\n";
1460 $_header .=
"Reply-To: ".$this->getReplyTo(
'addr').
"\r\n";
1463 $_header .=
'X-Mailer: Dolibarr version '.DOL_VERSION.
' (using SMTPs Mailer)'.
"\r\n";
1464 $_header .=
'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART ?
'MAIN_MAIL_USE_MULTI_PART' :
'No MAIN_MAIL_USE_MULTI_PART').
"\r\n";
1465 $_header .=
'Mime-Version: 1.0'.
"\r\n";
1482 if ($strType ==
'html') {
1483 $strMimeType =
'text/html';
1485 $strMimeType =
'text/plain';
1489 $strContent = preg_replace(
"/(?<!\r)\n/si",
"\r\n", $strContent);
1491 $strContentAltText =
'';
1492 if ($strType ==
'html') {
1494 $strContentAltText = preg_replace(
'/<head><title>.*<\/style><\/head>/',
'', $strContent);
1495 $strContentAltText = preg_replace(
"/<br\s*[^>]*>/",
" ", $strContentAltText);
1496 $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1497 $strContentAltText = trim(wordwrap($strContentAltText, 75,
"\r\n"));
1502 $strContent = rtrim(wordwrap($strContent, 75,
"\r\n"));
1504 $this->_msgContent[$strType] = array();
1506 $this->_msgContent[$strType][
'mimeType'] = $strMimeType;
1507 $this->_msgContent[$strType][
'data'] = $strContent;
1508 $this->_msgContent[$strType][
'dataText'] = $strContentAltText;
1511 $this->_msgContent[$strType][
'md5'] =
dol_hash($strContent, 3);
1529 $_types = array_keys($this->_msgContent);
1532 $keyCount = count($_types);
1535 if ($keyCount === 0) {
1536 die(
"Sorry, no content");
1537 } elseif ($keyCount === 1 && empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1540 $_msgData = $_msgData[$_types[0]];
1542 $content =
'Content-Type: '.$_msgData[
'mimeType'].
'; charset="'.$this->
getCharSet().
'"'.
"\r\n"
1543 .
'Content-Transfer-Encoding: '.$this->getTransEncodeType().
"\r\n"
1544 .
'Content-Disposition: inline'.
"\r\n"
1545 .
'Content-Description: Message'.
"\r\n";
1548 $content .=
'Content-MD5: '.$_msgData[
'md5'].
"\r\n";
1552 . $_msgData[
'data'].
"\r\n";
1553 } elseif ($keyCount >= 1 || !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1560 $content =
'Content-Type: multipart/mixed; boundary="'.$this->_getBoundary(
'mixed').
'"'.
"\r\n";
1564 $content .=
"Content-Transfer-Encoding: 8bit\r\n";
1567 $content .=
"--".$this->_getBoundary(
'mixed').
"\r\n";
1569 if (key_exists(
'image', $this->_msgContent)) {
1570 $content .=
'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary(
'alternative').
'"'.
"\r\n";
1572 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1580 foreach ($this->_msgContent as $type => $_content) {
1581 if ($type ==
'attachment') {
1583 foreach ($_content as $_file => $_data) {
1584 $content .=
"--".$this->_getBoundary(
'mixed').
"\r\n"
1585 .
'Content-Disposition: attachment; filename="'.$_data[
'fileName'].
'"'.
"\r\n"
1586 .
'Content-Type: '.$_data[
'mimeType'].
'; name="'.$_data[
'fileName'].
'"'.
"\r\n"
1587 .
'Content-Transfer-Encoding: base64'.
"\r\n"
1588 .
'Content-Description: '.$_data[
'fileName'].
"\r\n";
1589 if (!empty($_data[
'cid'])) {
1590 $content .=
"X-Attachment-Id: ".$_data[
'cid'].
"\r\n";
1591 $content .=
"Content-ID: <".$_data[
'cid'].
">\r\n";
1594 $content .=
'Content-MD5: '.$_data[
'md5'].
"\r\n";
1597 $content .=
"\r\n".$_data[
'data'].
"\r\n\r\n";
1599 } elseif ($type ==
'image') {
1602 foreach ($_content as $_image => $_data) {
1603 $content .=
"--".$this->_getBoundary(
'related').
"\r\n";
1605 $content .=
'Content-Type: '.$_data[
'mimeType'].
'; name="'.$_data[
'imageName'].
'"'.
"\r\n"
1606 .
'Content-Transfer-Encoding: base64'.
"\r\n"
1607 .
'Content-Disposition: inline; filename="'.$_data[
'imageName'].
'"'.
"\r\n"
1608 .
'Content-ID: <'.$_data[
'cid'].
'> '.
"\r\n";
1611 $content .=
'Content-MD5: '.$_data[
'md5'].
"\r\n";
1615 . $_data[
'data'].
"\r\n";
1619 $content .=
"--".$this->_getBoundary(
'related').
"--\r\n";
1620 $content .=
"\r\n--".$this->_getBoundary(
'alternative').
"--\r\n";
1623 if (key_exists(
'image', $this->_msgContent)) {
1624 $content .=
"Content-Type: text/plain; charset=".$this->getCharSet().
"\r\n";
1625 $content .=
"\r\n".($_content[
'dataText'] ? $_content[
'dataText'] : strip_tags($_content[
'data'])).
"\r\n";
1626 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1627 $content .=
'Content-Type: multipart/related; boundary="'.$this->_getBoundary(
'related').
'"'.
"\r\n";
1629 $content .=
"--".$this->_getBoundary(
'related').
"\r\n";
1632 if (!key_exists(
'image', $this->_msgContent) && $_content[
'dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1634 $content .=
'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary(
'alternative').
'"'.
"\r\n";
1636 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1638 $content .=
"Content-Type: text/plain; charset=".$this->getCharSet().
"\r\n";
1639 $content .=
"\r\n".$_content[
'dataText'].
"\r\n";
1640 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1643 $content .=
'Content-Type: '.$_content[
'mimeType'].
'; charset='.$this->
getCharSet();
1648 $content .=
'Content-MD5: '.$_content[
'md5'].
"\r\n";
1651 $content .=
"\r\n".$_content[
'data'].
"\r\n";
1653 if (!key_exists(
'image', $this->_msgContent) && $_content[
'dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1655 $content .=
"--".$this->_getBoundary(
'alternative').
"--\r\n";
1662 $content .=
"--".$this->_getBoundary(
'mixed').
'--'.
"\r\n";
1678 public function setAttachment($strContent, $strFileName =
'unknown', $strMimeType =
'unknown', $strCid =
'')
1681 $strContent = rtrim(chunk_split(base64_encode($strContent), 76,
"\r\n"));
1683 $this->_msgContent[
'attachment'][$strFileName][
'mimeType'] = $strMimeType;
1684 $this->_msgContent[
'attachment'][$strFileName][
'fileName'] = $strFileName;
1685 $this->_msgContent[
'attachment'][$strFileName][
'data'] = $strContent;
1686 $this->_msgContent[
'attachment'][$strFileName][
'cid'] = $strCid;
1689 $this->_msgContent[
'attachment'][$strFileName][
'md5'] =
dol_hash($strContent, 3);
1707 public function setImageInline($strContent, $strImageName =
'unknown', $strMimeType =
'unknown', $strImageCid =
'unknown')
1710 $this->_msgContent[
'image'][$strImageName][
'mimeType'] = $strMimeType;
1711 $this->_msgContent[
'image'][$strImageName][
'imageName'] = $strImageName;
1712 $this->_msgContent[
'image'][$strImageName][
'cid'] = $strImageCid;
1713 $this->_msgContent[
'image'][$strImageName][
'data'] = $strContent;
1716 $this->_msgContent[
'image'][$strImageName][
'md5'] =
dol_hash($strContent, 3);
1736 if ((is_numeric($_value)) &&
1737 (($_value >= 0) && ($_value <= 3))) {
1738 $this->_msgSensitivity = $_value;
1772 if ((is_numeric($_value)) &&
1773 (($_value >= 0) && ($_value <= 5))) {
1774 $this->_msgPriority = $_value;
1794 .
'X-Priority: '.$this->_msgPriority.
' ('.$this->_aryPriority[
$this->_msgPriority].
')'.
"\r\n";
1805 $this->_smtpMD5 = $_flag;
1829 $this->_msgXheader[] = $strXdata;
1850 $this->_smtpsBoundary =
"multipart_x.".time().
".x_boundary";
1851 $this->_smtpsRelatedBoundary =
'mul_'.dol_hash(uniqid(
"dolibarr2"), 3);
1852 $this->_smtpsAlternativeBoundary =
'mul_'.dol_hash(uniqid(
"dolibarr3"), 3);
1863 if ($type ==
'mixed') {
1865 } elseif ($type ==
'related') {
1867 } elseif ($type ==
'alternative') {
1892 $server_response =
'';
1897 while (substr($server_response, 3, 1) !=
' ' && $limit < 100) {
1898 if (!($server_response = fgets($socket, 256))) {
1899 $this->
_setErr(121,
"Couldn't get mail server response codes");
1903 $this->log .= $server_response;
1907 $this->lastretval = substr($server_response, 0, 3);
1909 if (!(substr($server_response, 0, 3) == $response)) {
1910 $this->
_setErr(120,
"Ran into problems sending Mail.\r\nResponse: ".$server_response);
1929 if ($this->_debug) {
1930 $this->log .= $_strSend;
1932 fputs($this->socket, $_strSend.$CRLF);
1933 if ($this->_debug) {
1934 $this->log .=
' ('.$_returnCode.
')'.$CRLF;
1938 return $this->
server_parse($this->socket, $_returnCode);
1956 $this->_smtpsErrors[] = array(
1971 if (is_array($this->_smtpsErrors)) {
1972 foreach ($this->_smtpsErrors as $_err => $_info) {
1973 $_errMsg[] =
'Error ['.$_info[
'num'].
']: '.$_info[
'msg'];
1977 return implode(
"\n", $_errMsg);