123 'Company Confidential');
226 private $_errorsTo =
'';
227 private $_deliveryReceipt = 0;
228 private $_trackId =
'';
229 private $_moreInHeader =
'';
255 $this->_deliveryReceipt = $_val;
265 return $this->_deliveryReceipt;
276 $this->_trackId = $_val;
287 $this->_moreinheader = $_val;
297 return $this->_trackId;
307 return $this->_moreinheader;
333 if ($_part ===
true) {
334 $_retValue = $this->_errorsTo;
336 $_retValue = $this->_errorsTo[$_part];
350 $this->_debug = $_vDebug;
361 $_aryToList = $this->getTO();
380 $usetls = preg_match(
'@tls://@i', $host);
382 $host = preg_replace(
'@tcp://@i',
'', $host);
383 $host = preg_replace(
'@ssl://@i',
'', $host);
384 $host = preg_replace(
'@tls://@i',
'', $host);
387 include_once DOL_DOCUMENT_ROOT.
'/core/lib/functions2.lib.php';
389 if ((!
is_ip($host)) && ((gethostbyname($host)) == $host)) {
390 $this->
_setErr(99, $host.
' is either offline or is an invalid host name.');
393 if (function_exists(
'stream_socket_client') && !empty($this->_options)) {
394 $socket_context = stream_context_create($this->_options);
395 $this->socket = @stream_socket_client(
396 preg_replace(
'@tls://@i',
'', $this->
getHost()).
401 STREAM_CLIENT_CONNECT,
405 $this->socket = @fsockopen(
406 preg_replace(
'@tls://@i',
'', $this->
getHost()),
415 if (is_resource($this->socket)) {
420 if (function_exists(
'stream_set_timeout')) {
421 stream_set_timeout($this->socket, $this->_smtpTimeout, 0);
425 if ($_retVal = $this->
server_parse($this->socket,
"220")) {
426 $_retVal = $this->socket;
431 if (empty($this->errstr)) {
432 $this->errstr =
'Failed to connect with fsockopen host='.$this->getHost().
' port='.$this->
getPort();
434 $this->
_setErr($this->errno, $this->errstr);
457 $usetls = preg_match(
'@tls://@i', $host);
459 $host = preg_replace(
'@tcp://@i',
'', $host);
460 $host = preg_replace(
'@ssl://@i',
'', $host);
461 $host = preg_replace(
'@tls://@i',
'', $host);
463 if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
464 $host =
'tls://'.$host;
469 if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
470 if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
472 $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
476 $hosth = $this->
getFrom(
'addr');
477 $hosth = preg_replace(
'/^.*</',
'', $hosth);
478 $hosth = preg_replace(
'/>.*$/',
'', $hosth);
479 $hosth = preg_replace(
'/.*@/',
'', $hosth);
538 $this->
_setErr(131,
'STARTTLS connection is not supported.');
549 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
550 if (defined(
'STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
551 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
552 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
555 if (!stream_socket_enable_crypto($this->socket,
true, $crypto_method)) {
556 $this->
_setErr(132,
'STARTTLS connection failed.');
562 $this->
_setErr(126,
'"'.$hosth.
'" does not support authenticated connections. Error after sending EHLO '.$hosth);
568 if (empty($conf->global->MAIL_SMTP_AUTH_TYPE)) {
569 $conf->global->MAIL_SMTP_AUTH_TYPE =
'LOGIN';
574 switch ($conf->global->MAIL_SMTP_AUTH_TYPE) {
582 $_retVal = $this->
socket_send_str(base64_encode(
"\0".$this->_smtpsID.
"\0".$this->_smtpsPW),
'235');
587 $xxxx =
"user=".$this->_smtpsID.
"\1auth=Bearer ".$token.
"\1\1";
588 $_retVal = $this->
socket_send_str(
'AUTH XOAUTH2 '.base64_encode($xxxx),
'235');
590 $this->
_setErr(130,
'Error when asking for AUTH XOAUTH2');
597 $this->
_setErr(130,
'Error when asking for AUTH LOGIN');
603 $_retVal = $this->
socket_send_str(base64_encode($this->_smtpsPW),
'235');
608 $this->
_setErr(130,
'Invalid Authentication Credentials.');
611 $this->
_setErr(126,
'"'.$host.
'" does not support authenticated connections. Error after sending EHLO '.$hosth);
634 if (!empty($this->_smtpsID) && !empty($this->_smtpsPW)) {
641 $usetls = preg_match(
'@tls://@i', $host);
643 $host = preg_replace(
'@tcp://@i',
'', $host);
644 $host = preg_replace(
'@ssl://@i',
'', $host);
645 $host = preg_replace(
'@tls://@i',
'', $host);
647 if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
648 $host =
'tls://'.$host;
653 if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
654 if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
656 $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
660 $hosth = $this->
getFrom(
'addr');
661 $hosth = preg_replace(
'/^.*</',
'', $hosth);
662 $hosth = preg_replace(
'/>.*$/',
'', $hosth);
663 $hosth = preg_replace(
'/.*@/',
'', $hosth);
676 if (!$resultmailfrom) {
677 fclose($this->socket);
712 fputs($this->socket,
'QUIT');
713 fclose($this->socket);
759 if (!empty($_strConfigPath)) {
762 if (!@include $_strConfigPath) {
763 $this->
_setErr(110,
'"'.$_strConfigPath.
'" is not a valid path.');
770 if ($_host = ini_get(
'SMTPs')) {
774 if ($_port = ini_get(
'smtp_port')) {
778 if ($_from = ini_get(
'sendmail_from')) {
798 if ((is_numeric($_type)) && (($_type >= 0) && ($_type <= 3))) {
799 $this->_transportType = $_type;
842 $this->_smtpsHost = $_strHost;
867 if ((is_numeric($_intPort)) &&
868 (($_intPort >= 1) && ($_intPort <= 65536))) {
869 $this->_smtpsPort = $_intPort;
892 $this->_smtpsID = $_strID;
913 $this->_smtpsPW = $_strPW;
936 $this->_smtpsCharSet = $_strCharSet;
967 if (array_search($_strTransEncode, $this->_smtpsTransEncodeTypes)) {
968 $this->_smtpsTransEncode = $_strTransEncode;
1000 if (array_search($_strTransEncodeType, $this->_smtpsTransEncodeTypes)) {
1001 $this->_smtpsTransEncodeType = $_strTransEncodeType;
1041 if ($_part ===
true) {
1044 $_retValue = $this->_msgFrom[$_part];
1059 $this->_msgReplyTo = $this->
_strip_email($_strReplyTo);
1073 if ($_part ===
true) {
1076 $_retValue = $this->_msgReplyTo[$_part];
1100 if (!empty($_addrList)) {
1102 if (is_string($_addrList)) {
1104 if (strstr($_addrList,
',')) {
1106 $_addrList = explode(
',', $_addrList);
1109 $_addrList = array($_addrList);
1114 foreach ($_addrList as $_strAddr) {
1116 $_strAddr = str_replace(
'>',
'', $_strAddr);
1120 $_tmpaddr = explode(
'<', $_strAddr);
1123 if (count($_tmpaddr) == 2) {
1124 $_tmpHost = explode(
'@', $_tmpaddr[1]);
1125 $_tmpaddr[0] = trim($_tmpaddr[0],
' ">');
1126 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = $_tmpaddr[0];
1130 $_strAddr = str_replace(
'<',
'', $_strAddr);
1132 $_tmpHost = explode(
'@', $_strAddr);
1133 $_tmpHost[0] = trim($_tmpHost[0]);
1134 $_tmpHost[1] = trim($_tmpHost[1]);
1136 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] =
'';
1141 $this->_msgRecipients = $aryHost;
1165 $_aryEmail[
'org'] = $_strAddr;
1168 $_strAddr = strtolower($_strAddr);
1171 $_strAddr = trim($_strAddr,
' ">');
1174 $_tmpAry = explode(
'<', $_strAddr);
1177 if (count($_tmpAry) == 2) {
1180 $_aryEmail[
'real'] = trim($_tmpAry[0],
' ">');
1183 $_aryEmail[
'addr'] = $_tmpAry[1];
1185 $_aryEmail[
'addr'] = $_tmpAry[0];
1189 list($_aryEmail[
'user'], $_aryEmail[
'host']) = explode(
'@', $_aryEmail[
'addr']);
1192 $_aryEmail[
'addr'] =
'<'.$_aryEmail[
'addr'].
'>';
1211 $_RCPT_list = array();
1214 foreach ($this->_msgRecipients as $_host => $_list) {
1215 foreach ($_list as $_subList) {
1216 foreach ($_subList as $_name => $_addr) {
1218 $_RCPT_list[] = $_name.
'@'.$_host;
1239 if ($this->_msgRecipients) {
1240 $_RCPT_list = array();
1242 foreach ($this->_msgRecipients as $_host => $_list) {
1243 if ($this->_msgRecipients[$_host][$_which]) {
1244 foreach ($this->_msgRecipients[$_host][$_which] as $_addr => $_realName) {
1246 $_realName =
'"'.$_realName.
'"';
1247 $_RCPT_list[] = $_realName.
' <'.$_addr.
'@'.$_host.
'>';
1249 $_RCPT_list[] = $_addr.
'@'.$_host;
1255 return implode(
', ', $_RCPT_list);
1257 $this->
_setErr(101,
'No eMail Address for message to be sent to.');
1261 $this->
_setErr(102,
'eMail type not defined.');
1344 $this->_msgSubject = $_strSubject;
1367 $_header =
'From: '.$this->getFrom(
'org').
"\r\n"
1368 .
'To: '.$this->getTO().
"\r\n";
1370 if ($this->
getCC()) {
1371 $_header .=
'Cc: '.$this->getCC().
"\r\n";
1385 $host = dol_getprefix(
'email');
1388 $_header .=
'Subject: '.$this->getSubject().
"\r\n";
1389 $_header .=
'Date: '.date(
"r").
"\r\n";
1394 $_header .=
'Message-ID: <'.time().
'.SMTPs-dolibarr-'.$trackid.
'@'.$host.
">\r\n";
1395 $_header .=
'References: <'.time().
'.SMTPs-dolibarr-'.$trackid.
'@'.$host.
">\r\n";
1396 $_header .=
'X-Dolibarr-TRACKID: '.$trackid.
'@'.$host.
"\r\n";
1398 $_header .=
'Message-ID: <'.time().
'.SMTPs@'.$host.
">\r\n";
1400 if (!empty($_SERVER[
'REMOTE_ADDR'])) {
1401 $_header .=
"X-RemoteAddr: ".$_SERVER[
'REMOTE_ADDR'].
"\r\n";
1412 $_header .=
'Sensitivity: '.$this->getSensitivity().
"\r\n";
1415 if ($this->_msgPriority != 3) {
1422 $_header .=
'Disposition-Notification-To: '.$this->getFrom(
'addr').
"\r\n";
1425 $_header .=
'Errors-To: '.$this->getErrorsTo(
'addr').
"\r\n";
1428 $_header .=
"Reply-To: ".$this->getReplyTo(
'addr').
"\r\n";
1431 $_header .=
'X-Mailer: Dolibarr version '.DOL_VERSION.
' (using SMTPs Mailer)'.
"\r\n";
1432 $_header .=
'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART ?
'MAIN_MAIL_USE_MULTI_PART' :
'No MAIN_MAIL_USE_MULTI_PART').
"\r\n";
1433 $_header .=
'Mime-Version: 1.0'.
"\r\n";
1450 if ($strType ==
'html') {
1451 $strMimeType =
'text/html';
1453 $strMimeType =
'text/plain';
1457 $strContent = preg_replace(
"/(?<!\r)\n/si",
"\r\n", $strContent);
1459 $strContentAltText =
'';
1460 if ($strType ==
'html') {
1462 $strContentAltText = preg_replace(
'/<head><title>.*<\/style><\/head>/',
'', $strContent);
1463 $strContentAltText = preg_replace(
"/<br\s*[^>]*>/",
" ", $strContentAltText);
1464 $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1465 $strContentAltText = trim(wordwrap($strContentAltText, 75,
"\r\n"));
1470 $strContent = rtrim(wordwrap($strContent, 75,
"\r\n"));
1472 $this->_msgContent[$strType] = array();
1474 $this->_msgContent[$strType][
'mimeType'] = $strMimeType;
1475 $this->_msgContent[$strType][
'data'] = $strContent;
1476 $this->_msgContent[$strType][
'dataText'] = $strContentAltText;
1479 $this->_msgContent[$strType][
'md5'] =
dol_hash($strContent, 3);
1497 $_types = array_keys($this->_msgContent);
1500 $keyCount = count($_types);
1503 if ($keyCount === 0) {
1504 die(
"Sorry, no content");
1505 } elseif ($keyCount === 1 && empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1508 $_msgData = $_msgData[$_types[0]];
1510 $content =
'Content-Type: '.$_msgData[
'mimeType'].
'; charset="'.$this->
getCharSet().
'"'.
"\r\n"
1511 .
'Content-Transfer-Encoding: '.$this->getTransEncodeType().
"\r\n"
1512 .
'Content-Disposition: inline'.
"\r\n"
1513 .
'Content-Description: Message'.
"\r\n";
1516 $content .=
'Content-MD5: '.$_msgData[
'md5'].
"\r\n";
1520 . $_msgData[
'data'].
"\r\n";
1521 } elseif ($keyCount >= 1 || !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1528 $content =
'Content-Type: multipart/mixed; boundary="'.$this->_getBoundary(
'mixed').
'"'.
"\r\n";
1532 $content .=
"Content-Transfer-Encoding: 8bit\r\n";
1535 $content .=
"--".$this->_getBoundary(
'mixed').
"\r\n";
1537 if (key_exists(
'image', $this->_msgContent)) {
1538 $content .=
'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary(
'alternative').
'"'.
"\r\n";
1540 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1548 foreach ($this->_msgContent as $type => $_content) {
1549 if ($type ==
'attachment') {
1551 foreach ($_content as $_file => $_data) {
1552 $content .=
"--".$this->_getBoundary(
'mixed').
"\r\n"
1553 .
'Content-Disposition: attachment; filename="'.$_data[
'fileName'].
'"'.
"\r\n"
1554 .
'Content-Type: '.$_data[
'mimeType'].
'; name="'.$_data[
'fileName'].
'"'.
"\r\n"
1555 .
'Content-Transfer-Encoding: base64'.
"\r\n"
1556 .
'Content-Description: '.$_data[
'fileName'].
"\r\n";
1559 $content .=
'Content-MD5: '.$_data[
'md5'].
"\r\n";
1562 $content .=
"\r\n".$_data[
'data'].
"\r\n\r\n";
1564 } elseif ($type ==
'image') {
1567 foreach ($_content as $_image => $_data) {
1568 $content .=
"--".$this->_getBoundary(
'related').
"\r\n";
1570 $content .=
'Content-Type: '.$_data[
'mimeType'].
'; name="'.$_data[
'imageName'].
'"'.
"\r\n"
1571 .
'Content-Transfer-Encoding: base64'.
"\r\n"
1572 .
'Content-Disposition: inline; filename="'.$_data[
'imageName'].
'"'.
"\r\n"
1573 .
'Content-ID: <'.$_data[
'cid'].
'> '.
"\r\n";
1576 $content .=
'Content-MD5: '.$_data[
'md5'].
"\r\n";
1580 . $_data[
'data'].
"\r\n";
1584 $content .=
"--".$this->_getBoundary(
'related').
"--\r\n";
1585 $content .=
"\r\n--".$this->_getBoundary(
'alternative').
"--\r\n";
1588 if (key_exists(
'image', $this->_msgContent)) {
1589 $content .=
"Content-Type: text/plain; charset=".$this->getCharSet().
"\r\n";
1590 $content .=
"\r\n".($_content[
'dataText'] ? $_content[
'dataText'] : strip_tags($_content[
'data'])).
"\r\n";
1591 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1592 $content .=
'Content-Type: multipart/related; boundary="'.$this->_getBoundary(
'related').
'"'.
"\r\n";
1594 $content .=
"--".$this->_getBoundary(
'related').
"\r\n";
1597 if (!key_exists(
'image', $this->_msgContent) && $_content[
'dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1599 $content .=
'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary(
'alternative').
'"'.
"\r\n";
1601 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1603 $content .=
"Content-Type: text/plain; charset=".$this->getCharSet().
"\r\n";
1604 $content .=
"\r\n".$_content[
'dataText'].
"\r\n";
1605 $content .=
"--".$this->_getBoundary(
'alternative').
"\r\n";
1608 $content .=
'Content-Type: '.$_content[
'mimeType'].
'; charset='.$this->
getCharSet();
1613 $content .=
'Content-MD5: '.$_content[
'md5'].
"\r\n";
1616 $content .=
"\r\n".$_content[
'data'].
"\r\n";
1618 if (!key_exists(
'image', $this->_msgContent) && $_content[
'dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1620 $content .=
"--".$this->_getBoundary(
'alternative').
"--\r\n";
1627 $content .=
"--".$this->_getBoundary(
'mixed').
'--'.
"\r\n";
1642 public function setAttachment($strContent, $strFileName =
'unknown', $strMimeType =
'unknown')
1645 $strContent = rtrim(chunk_split(base64_encode($strContent), 76,
"\r\n"));
1647 $this->_msgContent[
'attachment'][$strFileName][
'mimeType'] = $strMimeType;
1648 $this->_msgContent[
'attachment'][$strFileName][
'fileName'] = $strFileName;
1649 $this->_msgContent[
'attachment'][$strFileName][
'data'] = $strContent;
1652 $this->_msgContent[
'attachment'][$strFileName][
'md5'] =
dol_hash($strContent, 3);
1670 public function setImageInline($strContent, $strImageName =
'unknown', $strMimeType =
'unknown', $strImageCid =
'unknown')
1673 $this->_msgContent[
'image'][$strImageName][
'mimeType'] = $strMimeType;
1674 $this->_msgContent[
'image'][$strImageName][
'imageName'] = $strImageName;
1675 $this->_msgContent[
'image'][$strImageName][
'cid'] = $strImageCid;
1676 $this->_msgContent[
'image'][$strImageName][
'data'] = $strContent;
1679 $this->_msgContent[
'image'][$strImageName][
'md5'] =
dol_hash($strContent, 3);
1699 if ((is_numeric($_value)) &&
1700 (($_value >= 0) && ($_value <= 3))) {
1701 $this->_msgSensitivity = $_value;
1735 if ((is_numeric($_value)) &&
1736 (($_value >= 0) && ($_value <= 5))) {
1737 $this->_msgPriority = $_value;
1757 .
'X-Priority: '.$this->_msgPriority.
' ('.$this->_aryPriority[
$this->_msgPriority].
')'.
"\r\n";
1768 $this->_smtpMD5 = $_flag;
1792 $this->_msgXheader[] = $strXdata;
1813 $this->_smtpsBoundary =
"multipart_x.".time().
".x_boundary";
1814 $this->_smtpsRelatedBoundary =
'mul_'.dol_hash(uniqid(
"dolibarr2"), 3);
1815 $this->_smtpsAlternativeBoundary =
'mul_'.dol_hash(uniqid(
"dolibarr3"), 3);
1826 if ($type ==
'mixed') {
1828 } elseif ($type ==
'related') {
1830 } elseif ($type ==
'alternative') {
1853 $server_response =
'';
1858 while (substr($server_response, 3, 1) !=
' ' && $limit < 100) {
1859 if (!($server_response = fgets($socket, 256))) {
1860 $this->
_setErr(121,
"Couldn't get mail server response codes");
1864 $this->log .= $server_response;
1868 if (!(substr($server_response, 0, 3) == $response)) {
1869 $this->
_setErr(120,
"Ran into problems sending Mail.\r\nResponse: $server_response");
1888 if ($this->_debug) {
1889 $this->log .= $_strSend;
1891 fputs($this->socket, $_strSend.$CRLF);
1892 if ($this->_debug) {
1893 $this->log .=
' ('.$_returnCode.
')'.$CRLF;
1897 return $this->
server_parse($this->socket, $_returnCode);
1913 $this->_smtpsErrors[] = array(
1928 if (is_array($this->_smtpsErrors)) {
1929 foreach ($this->_smtpsErrors as $_err => $_info) {
1930 $_errMsg[] =
'Error ['.$_info[
'num'].
']: '.$_info[
'msg'];
1934 return implode(
"\n", $_errMsg);