dolibarr 21.0.0-alpha
smtps.class.php
Go to the documentation of this file.
1<?php
2/*
3 * Copyright (C) Walter Torres <walter@torres.ws> [with a *lot* of help!]
4 * Copyright (C) 2005-2015 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2006-2011 Regis Houssin
6 * Copyright (C) 2016 Jonathan TISSEAU <jonathan.tisseau@86dev.fr>
7 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
8 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
48class SMTPs
49{
53 private $_smtpsHost = 'localhost';
54
61 private $_smtpsPort = 25;
62
67 private $_smtpsID = null;
68
73 private $_smtpsPW = null;
74
78 private $_smtpsToken = null;
79
84 private $_msgFrom = null;
85
90 private $_msgReplyTo = null;
91
95 private $_msgInReplyTo = null;
96
100 private $_msgReferences = null;
101
107 private $_msgRecipients = null;
108
112 private $_msgSubject = null;
113
119 private $_msgContent = array();
120
124 private $_msgXheader = array();
125
131 private $_smtpsCharSet = 'iso-8859-1';
132
138 private $_msgSensitivity = 0;
139
143 private $_arySensitivity = array(false,
144 'Personal',
145 'Private',
146 'Company Confidential');
147
152 private $_msgPriority = 3;
153
157 private $_aryPriority = array('Bulk',
158 'Highest',
159 'High',
160 'Normal',
161 'Low',
162 'Lowest');
163
168 private $_smtpsTransEncodeType = 0;
169
173 private $_smtpsTransEncodeTypes = array('7bit', // Simple 7-bit ASCII
174 '8bit', // 8-bit coding with line termination characters
175 'base64', // 3 octets encoded into 4 sextets with offset
176 'binary', // Arbitrary binary stream
177 'mac-binhex40', // Macintosh binary to hex encoding
178 'quoted-printable', // Mostly 7-bit, with 8-bit characters encoded as "=HH"
179 'uuencode'); // UUENCODE encoding
180
186 private $_smtpsTransEncode = '7bit';
187
191 private $_smtpsBoundary = null;
192
196 private $_smtpsRelatedBoundary = null;
197
201 private $_smtpsAlternativeBoundary = null;
202
211 private $_transportType = 0;
212
217 private $_mailPath = '/usr/lib/sendmail'; // @phpstan-ignore-line
218
222 private $_smtpTimeout = 10;
223
227 private $_smtpMD5 = false;
228
232 private $_smtpsErrors = array();
233
241 private $_log_level = 0; // @phpstan-ignore-line
242
246 private $_debug = false;
247
248
249 // @CHANGE LDR
253 public $log = '';
257 public $lastretval = '';
258
262 public $socket;
263
267 public $errno;
268
272 public $errstr;
273
277 private $_errorsTo = array();
281 private $_deliveryReceipt = 0;
285 private $_trackId = '';
289 private $_moreinheader = '';
290
294 private $_options = array();
295
302 public function setOptions($_options = array())
303 {
304 $this->_options = $_options;
305 }
306
313 public function setDeliveryReceipt($_val = 0)
314 {
315 $this->_deliveryReceipt = $_val;
316 }
317
323 public function getDeliveryReceipt()
324 {
325 return $this->_deliveryReceipt;
326 }
327
334 public function setTrackId($_val = '')
335 {
336 $this->_trackId = $_val;
337 }
338
345 public function setMoreInHeader($_val = '')
346 {
347 $this->_moreinheader = $_val;
348 }
349
355 public function getTrackId()
356 {
357 return $this->_trackId;
358 }
359
365 public function getMoreInHeader()
366 {
367 return $this->_moreinheader;
368 }
369
376 public function setErrorsTo($_strErrorsTo)
377 {
378 if ($_strErrorsTo) {
379 $this->_errorsTo = $this->_strip_email($_strErrorsTo);
380 }
381 }
382
389 public function getErrorsTo($_part = true)
390 {
391 $_retValue = '';
392
393 if ($_part === true || !array_key_exists($_part, $this->_errorsTo)) {
394 $_retValue = $this->_errorsTo;
395 } else {
396 $_retValue = $this->_errorsTo[$_part];
397 }
398
399 return $_retValue;
400 }
401
408 public function setDebug($_vDebug = false)
409 {
410 $this->_debug = $_vDebug;
411 }
412
418 public function buildRCPTlist()
419 {
420 // Pull TO list
421 $_aryToList = $this->getTo();
422 }
423
424 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
430 private function _server_connect()
431 {
432 // phpcs:enable
433 // Default return value
434 $_retVal = true;
435
436 // We have to make sure the HOST given is valid
437 // This is done here because '@fsockopen' will not give me this
438 // information if it fails to connect because it can't find the HOST
439 $host = $this->getHost();
440 $usetls = preg_match('@tls://@i', $host);
441
442 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
443 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
444 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
445
446 // @CHANGE LDR
447 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
448
449 if ((!is_ip($host)) && ((gethostbyname($host)) == $host)) {
450 $this->_setErr(99, $host.' is either offline or is an invalid host name.');
451 $_retVal = false;
452 } else {
453 if (function_exists('stream_socket_client') && !empty($this->_options)) {
454 $socket_context = stream_context_create($this->_options); // An array of options for stream_context_create()
455 $this->socket = @stream_socket_client(
456 preg_replace('@tls://@i', '', $this->getHost()).// Host to 'hit', IP or domain
457 ':'.$this->getPort(), // which Port number to use
458 $this->errno, // actual system level error
459 $this->errstr, // and any text that goes with the error
460 $this->_smtpTimeout, // timeout for reading/writing data over the socket
461 STREAM_CLIENT_CONNECT,
462 $socket_context // Options for connection
463 );
464 } else {
465 $this->socket = @fsockopen(
466 preg_replace('@tls://@i', '', $this->getHost()), // Host to 'hit', IP or domain
467 $this->getPort(), // which Port number to use
468 $this->errno, // actual system level error
469 $this->errstr, // and any text that goes with the error
470 $this->_smtpTimeout // timeout for reading/writing data over the socket
471 );
472 }
473
474 //See if we can connect to the SMTP server
475 if (is_resource($this->socket)) {
476 // Fix from PHP SMTP class by 'Chris Ryan'
477 // Sometimes the SMTP server takes a little longer to respond
478 // so we will give it a longer timeout for the first read
479 // Windows still does not have support for this timeout function
480 if (function_exists('stream_set_timeout')) {
481 stream_set_timeout($this->socket, $this->_smtpTimeout, 0);
482 }
483
484 // Check response from Server
485 if ($_retVal = $this->server_parse($this->socket, "220")) {
486 $_retVal = $this->socket;
487 }
488 } else {
489 // This connection attempt failed.
490 // @CHANGE LDR
491 if (empty($this->errstr)) {
492 $this->errstr = 'Failed to connect with fsockopen host='.$this->getHost().' port='.$this->getPort();
493 }
494 $this->_setErr($this->errno, $this->errstr);
495 $_retVal = false;
496 }
497 }
498
499 return $_retVal;
500 }
501
502 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
508 private function _server_authenticate()
509 {
510 // phpcs:enable
511 global $conf;
512
513 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
514 // Send the RFC2554 specified EHLO.
515 // This improvement as provided by 'SirSir' to
516 // accommodate both SMTP AND ESMTP capable servers
517 $host = $this->getHost();
518 $usetls = preg_match('@tls://@i', $host);
519
520 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
521 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
522 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
523
524 if ($usetls && getDolGlobalString('MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO')) {
525 $host = 'tls://'.$host;
526 }
527
528 $hosth = $host; // so for example 'localhost' or 'smtp-relay.gmail.com'
529
530 if (getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO')) {
531 if (!is_numeric(getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO'))) {
532 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
533 $hosth = getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO');
534 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 1) {
535 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
536 // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
537 $hosth = (string) $this->getFrom('addr');
538 $hosth = preg_replace('/^.*</', '', $hosth);
539 $hosth = preg_replace('/>.*$/', '', $hosth);
540 $hosth = preg_replace('/.*@/', '', $hosth);
541 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 2) {
542 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
543 global $dolibarr_main_url_root;
544 $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
545 }
546 }
547
548 if ($_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
549 if ($usetls) {
550 /*
551 The following dialog illustrates how a client and server can start a TLS STARTTLS session:
552 S: <waits for connection on TCP port 25>
553 C: <opens connection>
554 S: 220 mail.imc.org SMTP service ready
555 C: EHLO mail.ietf.org
556 S: 250-mail.imc.org offers a warm hug of welcome
557 S: 250 STARTTLS
558 C: STARTTLS
559 S: 220 Go ahead
560 C: <starts TLS negotiation>
561 C & S: <negotiate a TLS session>
562 C & S: <check result of negotiation>
563 // Second pass EHLO
564 C: EHLO client-domain.com
565 S: 250-server-domain.com
566 S: 250 AUTH LOGIN
567 C: <continues by sending an SMTP command
568
569 Another example here:
570 S: 220 smtp.server.com Simple Mail Transfer Service Ready
571 C: EHLO client.example.com
572 S: 250-smtp.server.com Hello client.example.com
573 S: 250-SIZE 1000000
574 S: 250-AUTH LOGIN PLAIN CRAM-MD5
575 S: 250-STARTTLS
576 S: 250 HELP
577 C: STARTTLS
578 S: 220 TLS go ahead
579 C: EHLO client.example.com *
580 S: 250-smtp.server.com Hello client.example.com
581 S: 250-SIZE 1000000
582 S: 250-AUTH LOGIN PLAIN CRAM-MD5
583 S: 250 HELP
584 C: AUTH LOGIN
585 S: 334 VXNlcm5hbWU6
586 C: adlxdkej
587 S: 334 UGFzc3dvcmQ6
588 C: lkujsefxlj
589 S: 235 2.7.0 Authentication successful
590 C: MAIL FROM:<mail@samlogic.com>
591 S: 250 OK
592 C: RCPT TO:<john@mail.com>
593 S: 250 OK
594 C: DATA
595 S: 354 Send message, end with a "." on a line by itself
596 C: <The message data (body text, subject, e-mail header, attachments etc) is sent>
597 S .
598 S: 250 OK, message accepted for delivery: queued as 12345
599 C: QUIT
600 S: 221 Bye
601 */
602 if (!$_retVal = $this->socket_send_str('STARTTLS', '220')) {
603 $this->_setErr(131, 'STARTTLS connection is not supported.');
604 return $_retVal;
605 }
606
607 // Before 5.6.7:
608 // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_SSLv2_CLIENT|STREAM_CRYPTO_METHOD_SSLv3_CLIENT
609 // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
610 // PHP >= 5.6.7:
611 // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
612 // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
613
614 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
615 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
616 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
617 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
618 }
619
620 if (!stream_socket_enable_crypto($this->socket, true, $crypto_method)) {
621 $this->_setErr(132, 'STARTTLS connection failed.');
622 return $_retVal;
623 }
624 // Most servers expect a 2nd pass of EHLO after TLS is established to get another time
625 // the answer with list of supported AUTH methods. They may differs between non STARTTLS and with STARTTLS.
626 if (! $_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
627 $this->_setErr(126, '"'.$hosth.'" does not support authenticated connections or temporary error. Error after 2nd sending EHLO '.$hosth.' : '.$this->lastretval);
628 return $_retVal;
629 }
630 }
631
632 // Default authentication method is LOGIN
633 if (!getDolGlobalString('MAIN_MAIL_SMTPS_AUTH_TYPE')) {
634 $conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE = 'LOGIN';
635 }
636
637 // Send Authentication to Server
638 // Check for errors along the way
639 switch ($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE) {
640 case 'NONE':
641 // Do not send the 'AUTH type' message. For test purpose, if you don't need authentication, it is better to not enter login/pass into setup.
642 $_retVal = true;
643 break;
644 case 'PLAIN':
645 $this->socket_send_str('AUTH PLAIN', '334');
646 // The error here just means the ID/password combo doesn't work.
647 $_retVal = $this->socket_send_str(base64_encode("\0".$this->_smtpsID."\0".$this->_smtpsPW), '235');
648 break;
649 case 'XOAUTH2':
650 // "user=$email\1auth=Bearer $token\1\1"
651 $user = $this->_smtpsID;
652 $token = $this->_smtpsToken;
653 $initRes = "user=".$user."\001auth=Bearer ".$token."\001\001";
654 $_retVal = $this->socket_send_str('AUTH XOAUTH2 '.base64_encode($initRes), '235');
655 if (!$_retVal) {
656 $this->_setErr(130, 'Error when asking for AUTH XOAUTH2');
657 }
658 break;
659 case 'LOGIN': // most common case
660 default:
661 $_retVal = $this->socket_send_str('AUTH LOGIN', '334');
662 if (!$_retVal) {
663 $this->_setErr(130, 'Error when asking for AUTH LOGIN');
664 } else {
665 // User name will not return any error, server will take anything we give it.
666 $this->socket_send_str(base64_encode((string) $this->_smtpsID), '334');
667 // The error here just means the ID/password combo doesn't work.
668 // There is no method to determine which is the problem, ID or password
669 $_retVal = $this->socket_send_str(base64_encode((string) $this->_smtpsPW), '235');
670 }
671 break;
672 }
673 if (!$_retVal) {
674 $this->_setErr(130, 'Invalid Authentication Credentials.');
675 }
676 } else {
677 $this->_setErr(126, '"'.$host.'" refused the EHLO command. Error after sending EHLO '.$hosth.' : '.$this->lastretval);
678 }
679
680 return $_retVal;
681 }
682
688 public function sendMsg()
689 {
690 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
691
692 // Default return value
693 $_retVal = false;
694
695 // Connect to Server
696 if ($this->socket = $this->_server_connect()) {
697 // If a User ID *and* a password is given, assume Authentication is desired
698 if (!empty($this->_smtpsID) && (!empty($this->_smtpsPW) || !empty($this->_smtpsToken))) {
699 // Send the RFC2554 specified EHLO.
700 $_retVal = $this->_server_authenticate();
701 } else {
702 // This is a "normal" SMTP Server "handshack"
703 // Send the RFC821 specified HELO.
704 $host = $this->getHost();
705 $usetls = preg_match('@tls://@i', $host);
706
707 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
708 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
709 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
710
711 if ($usetls && getDolGlobalString('MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO')) {
712 $host = 'tls://'.$host;
713 }
714
715 $hosth = $host;
716
717 if (getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO')) {
718 if (!is_numeric(getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO'))) {
719 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
720 $hosth = getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO');
721 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 1) {
722 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
723 // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
724 $hosth = (string) $this->getFrom('addr');
725 $hosth = preg_replace('/^.*</', '', $hosth);
726 $hosth = preg_replace('/>.*$/', '', $hosth);
727 $hosth = preg_replace('/.*@/', '', $hosth);
728 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 2) {
729 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
730 global $dolibarr_main_url_root;
731 $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
732 }
733 }
734
735 // Send the HELO message to the SMTP server
736 $_retVal = $this->socket_send_str('HELO '.$hosth, '250');
737 }
738
739 // Well, did we get the server answer with correct code ?
740 if ($_retVal) {
741 // From this point onward most server response codes should be 250
742 // Specify who the mail is from....
743 // This has to be the raw email address, strip the "name" off
744 $resultmailfrom = $this->socket_send_str('MAIL FROM: '.$this->getFrom('addr'), '250');
745 if (!$resultmailfrom) {
746 fclose($this->socket);
747 return false;
748 }
749
750 // 'RCPT TO:' must be given a single address, so this has to loop
751 // through the list of addresses, regardless of TO, CC or BCC
752 // and send it out "single file"
753 foreach ($this->get_RCPT_list() as $_address) {
754 /* Note:
755 * BCC email addresses must be listed in the RCPT TO command list,
756 * but the BCC header should not be printed under the DATA command.
757 * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
758 */
759
760 /*
761 * TODO
762 * After each 'RCPT TO:' is sent, we need to make sure it was kosher,
763 * if not, the whole message will fail
764 * If any email address fails, we will need to RESET the connection,
765 * mark the last address as "bad" and start the address loop over again.
766 * If any address fails, the entire message fails.
767 */
768 $this->socket_send_str('RCPT TO: <'.$_address.'>', '250');
769 }
770
771 // Tell the server we are ready to start sending data
772 // with any custom headers...
773 // This is the last response code we look for until the end of the message.
774 $this->socket_send_str('DATA', '354');
775
776 // Now we are ready for the message...
777 // Ok, all the ingredients are mixed in let's cook this puppy...
778 $this->socket_send_str($this->getHeader().$this->getBodyContent()."\r\n".'.', '250');
779
780 // Now tell the server we are done and close the socket...
781 fwrite($this->socket, 'QUIT');
782 } else {
783 // We got error code into $this->lastretval
784 }
785
786 fclose($this->socket);
787 }
788
789 return $_retVal;
790 }
791
792 // =============================================================
793 // ** Setter & Getter methods
794
795 // ** Basic System configuration
796
822 public function setConfig($_strConfigPath = null)
823 {
828 $_retVal = true;
829
830 // if we have a path...
831 if (!empty($_strConfigPath)) {
832 // If the path is not valid, this will NOT generate an error,
833 // it will simply return false.
834 if (!@include $_strConfigPath) {
835 $this->_setErr(110, '"'.$_strConfigPath.'" is not a valid path.');
836 $_retVal = false;
837 }
838 } else {
839 // Read the Systems php.ini file
840 // Set these properties ONLY if they are set in the php.ini file.
841 // Otherwise the default values will be used.
842 if ($_host = ini_get('SMTPs')) {
843 $this->setHost($_host);
844 }
845
846 if ($_port = ini_get('smtp_port')) {
847 $this->setPort($_port);
848 }
849
850 if ($_from = ini_get('sendmail_from')) {
851 $this->setFrom($_from);
852 }
853 }
854
855 // Send back what we have
856 return $_retVal;
857 }
858
868 public function setTransportType($_type = 0)
869 {
870 if ((is_numeric($_type)) && (($_type >= 0) && ($_type <= 3))) {
871 $this->_transportType = $_type;
872 }
873 }
874
883 public function getTransportType()
884 {
885 return $this->_transportType;
886 }
887
895 public function setMailPath($_path)
896 {
897 // This feature is not yet implemented
898 return true;
899
900 //if ( $_path ) $this->_mailPath = $_path;
901 }
902
911 public function setHost($_strHost)
912 {
913 if ($_strHost) {
914 $this->_smtpsHost = $_strHost;
915 }
916 }
917
924 public function getHost()
925 {
926 return $this->_smtpsHost;
927 }
928
937 public function setPort($_intPort)
938 {
939 if ((is_numeric($_intPort)) &&
940 (($_intPort >= 1) && ($_intPort <= 65536))) {
941 $this->_smtpsPort = (int) $_intPort;
942 }
943 }
944
951 public function getPort()
952 {
953 return (int) $this->_smtpsPort;
954 }
955
962 public function setID($_strID)
963 {
964 $this->_smtpsID = $_strID;
965 }
966
972 public function getID()
973 {
974 return $this->_smtpsID;
975 }
976
983 public function setPW($_strPW)
984 {
985 $this->_smtpsPW = $_strPW;
986 }
987
993 public function getPW()
994 {
995 return $this->_smtpsPW;
996 }
997
1004 public function setToken($_strToken)
1005 {
1006 $this->_smtpsToken = $_strToken;
1007 }
1008
1014 public function getToken()
1015 {
1016 return $this->_smtpsToken;
1017 }
1018
1026 public function setCharSet($_strCharSet)
1027 {
1028 if ($_strCharSet) {
1029 $this->_smtpsCharSet = $_strCharSet;
1030 }
1031 }
1032
1038 public function getCharSet()
1039 {
1040 return $this->_smtpsCharSet;
1041 }
1042
1058 public function setTransEncode($_strTransEncode)
1059 {
1060 if (array_search($_strTransEncode, $this->_smtpsTransEncodeTypes)) {
1061 $this->_smtpsTransEncode = $_strTransEncode;
1062 }
1063 }
1064
1070 public function getTransEncode()
1071 {
1072 return $this->_smtpsTransEncode;
1073 }
1074
1091 public function setTransEncodeType($_strTransEncodeType)
1092 {
1093 if (array_search($_strTransEncodeType, $this->_smtpsTransEncodeTypes)) {
1094 $this->_smtpsTransEncodeType = $_strTransEncodeType;
1095 }
1096 }
1097
1103 public function getTransEncodeType()
1104 {
1105 return $this->_smtpsTransEncodeTypes[$this->_smtpsTransEncodeType];
1106 }
1107
1108
1109 // ** Message Construction
1110
1117 public function setFrom($_strFrom)
1118 {
1119 if ($_strFrom) {
1120 $this->_msgFrom = $this->_strip_email($_strFrom);
1121 }
1122 }
1123
1130 public function getFrom($_part = true)
1131 {
1132 $_retValue = '';
1133
1134 if ($_part === true || $this->_msgFrom === null) {
1135 $_retValue = $this->_msgFrom;
1136 } else {
1137 $_retValue = $this->_msgFrom[$_part];
1138 }
1139
1140 return $_retValue;
1141 }
1142
1149 public function setReplyTo($_strReplyTo)
1150 {
1151 if ($_strReplyTo) {
1152 $this->_msgReplyTo = $this->_strip_email($_strReplyTo);
1153 }
1154 }
1155
1162 public function getReplyTo($_part = true)
1163 {
1164 $_retValue = '';
1165
1166 if ($_part === true) {
1167 $_retValue = $this->_msgReplyTo;
1168 } else {
1169 $_retValue = $this->_msgReplyTo[$_part];
1170 }
1171
1172 return $_retValue;
1173 }
1174
1181 public function setInReplyTo($_strInReplyTo)
1182 {
1183 if ($_strInReplyTo) {
1184 $this->_msgInReplyTo = $_strInReplyTo;
1185 }
1186 }
1187
1193 public function getInReplyTo()
1194 {
1195 $_retValue = $this->_msgInReplyTo;
1196
1197 return $_retValue;
1198 }
1199
1206 public function setReferences($_strReferences)
1207 {
1208 if ($_strReferences) {
1209 $this->_msgReferences = $_strReferences;
1210 }
1211 }
1212
1218 public function getReferences()
1219 {
1220 $_retValue = $this->_msgReferences;
1221
1222 return $_retValue;
1223 }
1224
1235 private function _buildAddrList($_type, $_addrList)
1236 {
1237 // Pull existing list
1238 $aryHost = $this->_msgRecipients;
1239
1240 // Only run this if we have something
1241 if (!empty($_addrList)) {
1242 // $_addrList can be a STRING or an array
1243 if (is_string($_addrList)) {
1244 // This could be a COMMA delimited string
1245 if (strstr($_addrList, ',')) {
1246 // "explode "list" into an array
1247 $_addrList = explode(',', $_addrList);
1248 } else {
1249 // Stick it in an array
1250 $_addrList = array($_addrList);
1251 }
1252 }
1253
1254 // take the array of addresses and split them further
1255 foreach ($_addrList as $_strAddr) {
1256 // Strip off the end '>'
1257 $_strAddr = str_replace('>', '', $_strAddr);
1258
1259 // Separate "Real Name" from eMail address
1260 $_tmpaddr = null;
1261 $_tmpaddr = explode('<', $_strAddr);
1262
1263 // We have a "Real Name" and eMail address
1264 if (count($_tmpaddr) == 2) {
1265 $_tmpHost = explode('@', $_tmpaddr[1]);
1266 $_tmpaddr[0] = trim($_tmpaddr[0], ' ">');
1267 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = $_tmpaddr[0];
1268 } else {
1269 // We only have an eMail address
1270 // Strip off the beginning '<'
1271 $_strAddr = str_replace('<', '', $_strAddr);
1272
1273 $_tmpHost = explode('@', $_strAddr);
1274 $_tmpHost[0] = trim($_tmpHost[0]);
1275 $_tmpHost[1] = trim($_tmpHost[1]);
1276
1277 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = '';
1278 }
1279 }
1280 }
1281 // replace list
1282 $this->_msgRecipients = $aryHost;
1283 }
1284
1285 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1302 private function _strip_email($_strAddr)
1303 {
1304 // phpcs:enable
1305 $_aryEmail = array();
1306 // Keep the original
1307 $_aryEmail['org'] = $_strAddr;
1308
1309 // Set entire string to Lower Case
1310 $_strAddr = strtolower($_strAddr);
1311
1312 // Drop "stuff' off the end
1313 $_strAddr = trim($_strAddr, ' ">');
1314
1315 // Separate "Real Name" from eMail address, if we have one
1316 $_tmpAry = explode('<', $_strAddr);
1317
1318 // Do we have a "Real name"
1319 if (count($_tmpAry) == 2) {
1320 // We may not really have a "Real Name"
1321 if ($_tmpAry[0]) {
1322 $_aryEmail['real'] = trim($_tmpAry[0], ' ">');
1323 }
1324
1325 $_aryEmail['addr'] = $_tmpAry[1];
1326 } else {
1327 $_aryEmail['addr'] = $_tmpAry[0];
1328 }
1329
1330 // Pull User Name and Host.tld apart
1331 $_tmpHost = explode('@', $_aryEmail['addr']);
1332 $_aryEmail['user'] = $_tmpHost[0];
1333 $_aryEmail['host'] = $_tmpHost[1];
1334
1335 // Put the brackets back around the address
1336 $_aryEmail['addr'] = '<'.$_aryEmail['addr'].'>';
1337
1338 return $_aryEmail;
1339 }
1340
1341 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1349 public function get_RCPT_list()
1350 {
1351 // phpcs:enable
1355 $_RCPT_list = array();
1356
1357 // walk down Recipients array and pull just email addresses
1358 foreach ($this->_msgRecipients as $_host => $_list) {
1359 foreach ($_list as $_subList) {
1360 foreach ($_subList as $_name => $_addr) {
1361 // build RCPT list
1362 $_RCPT_list[] = $_name.'@'.$_host;
1363 }
1364 }
1365 }
1366
1367 return $_RCPT_list;
1368 }
1369
1370 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1377 public function get_email_list($_which = null)
1378 {
1379 // phpcs:enable
1380 // We need to know which address segment to pull
1381 if ($_which) {
1382 // Make sure we have addresses to process
1383 if ($this->_msgRecipients) {
1384 $_RCPT_list = array();
1385 // walk down Recipients array and pull just email addresses
1386 foreach ($this->_msgRecipients as $_host => $_list) {
1387 if (!empty($this->_msgRecipients[$_host][$_which])) {
1388 foreach ($this->_msgRecipients[$_host][$_which] as $_addr => $_realName) {
1389 if ($_realName) { // @CHANGE LDR
1390 $_realName = '"'.$_realName.'"';
1391 $_RCPT_list[] = $_realName.' <'.$_addr.'@'.$_host.'>';
1392 } else {
1393 $_RCPT_list[] = $_addr.'@'.$_host;
1394 }
1395 }
1396 }
1397 }
1398
1399 return implode(', ', $_RCPT_list);
1400 } else {
1401 $this->_setErr(101, 'No eMail Address for message to be sent to.');
1402 return false;
1403 }
1404 } else {
1405 $this->_setErr(102, 'eMail type not defined.');
1406 return false;
1407 }
1408 }
1409
1416 public function setTO($_addrTo)
1417 {
1418 if ($_addrTo) {
1419 $this->_buildAddrList('to', $_addrTo);
1420 }
1421 }
1422
1428 public function getTo()
1429 {
1430 return $this->get_email_list('to');
1431 }
1432
1439 public function setCC($_strCC)
1440 {
1441 if ($_strCC) {
1442 $this->_buildAddrList('cc', $_strCC);
1443 }
1444 }
1445
1451 public function getCC()
1452 {
1453 return $this->get_email_list('cc');
1454 }
1455
1462 public function setBCC($_strBCC)
1463 {
1464 if ($_strBCC) {
1465 $this->_buildAddrList('bcc', $_strBCC);
1466 }
1467 }
1468
1474 public function getBCC()
1475 {
1476 return $this->get_email_list('bcc');
1477 }
1478
1485 public function setSubject($_strSubject = '')
1486 {
1487 if ($_strSubject) {
1488 $this->_msgSubject = $_strSubject;
1489 }
1490 }
1491
1497 public function getSubject()
1498 {
1499 return $this->_msgSubject;
1500 }
1501
1507 public function getHeader()
1508 {
1509 global $conf;
1510
1511 $_header = 'From: '.$this->getFrom('org')."\r\n"
1512 . 'To: '.$this->getTo()."\r\n";
1513
1514 if ($this->getCC()) {
1515 $_header .= 'Cc: '.$this->getCC()."\r\n";
1516 }
1517
1518 /* Note:
1519 * BCC email addresses must be listed in the RCPT TO command list,
1520 * but the BCC header should not be printed under the DATA command.
1521 * So it is included into the function sendMsg() but not here.
1522 * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
1523 */
1524 /*
1525 if ( $this->getBCC() )
1526 $_header .= 'Bcc: ' . $this->getBCC() . "\r\n";
1527 */
1528
1529 $host = dol_getprefix('email');
1530
1531 //NOTE: Message-ID should probably contain the username of the user who sent the msg
1532 $_header .= 'Subject: '.$this->getSubject()."\r\n";
1533 $_header .= 'Date: '.date("r")."\r\n";
1534
1535 $trackid = $this->getTrackId();
1536 if ($trackid) {
1537 $_header .= 'Message-ID: <'.time().'.SMTPs-dolibarr-'.$trackid.'@'.$host.">\r\n";
1538 $_header .= 'X-Dolibarr-TRACKID: '.$trackid.'@'.$host."\r\n";
1539 } else {
1540 $_header .= 'Message-ID: <'.time().'.SMTPs@'.$host.">\r\n";
1541 }
1542 if (!empty($_SERVER['REMOTE_ADDR'])) {
1543 $_header .= "X-RemoteAddr: ".$_SERVER['REMOTE_ADDR']."\r\n";
1544 }
1545 if ($this->getMoreInHeader()) {
1546 $_header .= $this->getMoreInHeader(); // Value must include the "\r\n";
1547 }
1548
1549 if ($this->getSensitivity()) {
1550 $_header .= 'Sensitivity: '.$this->getSensitivity()."\r\n";
1551 }
1552
1553 if ($this->_msgPriority != 3) {
1554 $_header .= $this->getPriority();
1555 }
1556
1557
1558 // @CHANGE LDR
1559 if ($this->getDeliveryReceipt()) {
1560 $_header .= 'Disposition-Notification-To: '.$this->getFrom('addr')."\r\n";
1561 }
1562 if ($this->getErrorsTo()) {
1563 $_header .= 'Errors-To: '.$this->getErrorsTo('addr')."\r\n";
1564 }
1565 if ($this->getReplyTo()) {
1566 $_header .= "Reply-To: ".$this->getReplyTo('addr')."\r\n";
1567 }
1568
1569 $_header .= 'X-Mailer: Dolibarr version '.DOL_VERSION.' (using SMTPs Mailer)'."\r\n";
1570 $_header .= 'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART ? 'MAIN_MAIL_USE_MULTI_PART' : 'No MAIN_MAIL_USE_MULTI_PART')."\r\n";
1571 $_header .= 'Mime-Version: 1.0'."\r\n";
1572
1573 // Add also $this->references and In-Reply-To
1574 if ($this->getInReplyTo()) {
1575 $_header .= "In-Reply-To: ".$this->getInReplyTo()."\r\n";
1576 }
1577 if ($this->getReferences()) {
1578 $_header .= "References: ".$this->getReferences()."\r\n";
1579 }
1580
1581 return $_header;
1582 }
1583
1591 public function setBodyContent($strContent, $strType = 'plain')
1592 {
1593 //if ( $strContent )
1594 //{
1595 if ($strType == 'html') {
1596 $strMimeType = 'text/html';
1597 } else {
1598 $strMimeType = 'text/plain';
1599 }
1600
1601 // Make RFC821 Compliant, replace bare linefeeds
1602 $strContent = preg_replace("/(?<!\r)\n/si", "\r\n", $strContent);
1603
1604 $strContentAltText = '';
1605 if ($strType == 'html') {
1606 // Similar code to forge a text from html is also in CMailFile.class.php
1607 $strContentAltText = preg_replace('/<head><title>.*<\/style><\/head>/', '', $strContent);
1608 $strContentAltText = preg_replace("/<br\s*[^>]*>/", " ", $strContentAltText);
1609 $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1610 $strContentAltText = trim(wordwrap($strContentAltText, 75, "\r\n"));
1611 }
1612
1613 // Make RFC2045 Compliant
1614 //$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
1615 $strContent = rtrim(wordwrap($strContent, 75, "\r\n")); // TODO Using this method creates unexpected line break on text/plain content.
1616
1617 $this->_msgContent[$strType] = array();
1618
1619 $this->_msgContent[$strType]['mimeType'] = $strMimeType;
1620 $this->_msgContent[$strType]['data'] = $strContent;
1621 $this->_msgContent[$strType]['dataText'] = $strContentAltText;
1622
1623 if ($this->getMD5flag()) {
1624 $this->_msgContent[$strType]['md5'] = dol_hash($strContent, '3');
1625 }
1626 //}
1627 }
1628
1634 public function getBodyContent()
1635 {
1636 global $conf;
1637
1638 // Generate a new Boundary string
1639 $this->_setBoundary();
1640
1641 // What type[s] of content do we have
1642 $_types = array_keys($this->_msgContent);
1643
1644 // How many content types do we have
1645 $keyCount = count($_types);
1646
1647 // If we have ZERO, we have a problem
1648 if ($keyCount === 0) {
1649 die("Sorry, no content");
1650 } elseif ($keyCount === 1 && !getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1651 // If we have ONE, we can use the simple format
1652 $_msgData = $this->_msgContent;
1653 $_msgData = $_msgData[$_types[0]];
1654
1655 $content = 'Content-Type: '.$_msgData['mimeType'].'; charset="'.$this->getCharSet().'"'."\r\n"
1656 . 'Content-Transfer-Encoding: '.$this->getTransEncodeType()."\r\n"
1657 . 'Content-Disposition: inline'."\r\n"
1658 . 'Content-Description: Message'."\r\n";
1659
1660 if ($this->getMD5flag()) {
1661 $content .= 'Content-MD5: '.$_msgData['md5']."\r\n";
1662 }
1663
1664 $content .= "\r\n"
1665 . $_msgData['data']."\r\n";
1666 } elseif ($keyCount >= 1 || getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1667 // If we have more than ONE, we use the multi-part format
1668 // Since this is an actual multi-part message
1669 // We need to define a content message Boundary
1670 // NOTE: This was 'multipart/alternative', but Windows based mail servers have issues with this.
1671
1672 //$content = 'Content-Type: multipart/related; boundary="' . $this->_getBoundary() . '"' . "\r\n";
1673 $content = 'Content-Type: multipart/mixed; boundary="'.$this->_getBoundary('mixed').'"'."\r\n";
1674
1675 // . "\r\n"
1676 // . 'This is a multi-part message in MIME format.' . "\r\n";
1677 $content .= "Content-Transfer-Encoding: 8bit\r\n";
1678 $content .= "\r\n";
1679
1680 $content .= "--".$this->_getBoundary('mixed')."\r\n";
1681
1682 if (array_key_exists('image', $this->_msgContent)) { // If inline image found
1683 $content .= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"'."\r\n";
1684 $content .= "\r\n";
1685 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1686 }
1687
1688
1689 // $this->_msgContent must be sorted with key 'text' or 'html' first then 'image' then 'attachment'
1690
1691
1692 // Loop through message content array
1693 foreach ($this->_msgContent as $type => $_content) {
1694 if ($type == 'attachment') {
1695 // loop through all attachments
1696 foreach ($_content as $_file => $_data) {
1697 $content .= "--".$this->_getBoundary('mixed')."\r\n"
1698 . 'Content-Disposition: attachment; filename="'.$_data['fileName'].'"'."\r\n"
1699 . 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['fileName'].'"'."\r\n"
1700 . 'Content-Transfer-Encoding: base64'."\r\n"
1701 . 'Content-Description: '.$_data['fileName']."\r\n";
1702 if (!empty($_data['cid'])) {
1703 $content .= "X-Attachment-Id: ".$_data['cid']."\r\n";
1704 $content .= "Content-ID: <".$_data['cid'].">\r\n";
1705 }
1706 if ($this->getMD5flag()) {
1707 $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1708 }
1709
1710 $content .= "\r\n".$_data['data']."\r\n\r\n";
1711 }
1712 } elseif ($type == 'image') {
1713 // @CHANGE LDR
1714 // loop through all images
1715 foreach ($_content as $_image => $_data) {
1716 $content .= "--".$this->_getBoundary('related')."\r\n"; // always related for an inline image
1717
1718 $content .= 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['imageName'].'"'."\r\n"
1719 . 'Content-Transfer-Encoding: base64'."\r\n"
1720 . 'Content-Disposition: inline; filename="'.$_data['imageName'].'"'."\r\n"
1721 . 'Content-ID: <'.$_data['cid'].'> '."\r\n";
1722
1723 if ($this->getMD5flag()) {
1724 $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1725 }
1726
1727 $content .= "\r\n"
1728 . $_data['data']."\r\n";
1729 }
1730
1731 // always end related and end alternative after inline images
1732 $content .= "--".$this->_getBoundary('related')."--\r\n";
1733 $content .= "\r\n--".$this->_getBoundary('alternative')."--\r\n";
1734 $content .= "\r\n";
1735 } else {
1736 if (array_key_exists('image', $this->_msgContent)) {
1737 $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1738 $content .= "\r\n".($_content['dataText'] ? $_content['dataText'] : strip_tags($_content['data']))."\r\n"; // Add plain text message
1739 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1740 $content .= 'Content-Type: multipart/related; boundary="'.$this->_getBoundary('related').'"'."\r\n";
1741 $content .= "\r\n";
1742 $content .= "--".$this->_getBoundary('related')."\r\n";
1743 }
1744
1745 if (!array_key_exists('image', $this->_msgContent) && $_content['dataText'] && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1746 // Add plain text message part before html part
1747 $content .= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"'."\r\n";
1748 $content .= "\r\n";
1749 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1750
1751 $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1752 $content .= "\r\n".$_content['dataText']."\r\n";
1753 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1754 }
1755
1756 $content .= 'Content-Type: '.$_content['mimeType'].'; charset='.$this->getCharSet();
1757
1758 $content .= "\r\n";
1759
1760 if ($this->getMD5flag()) {
1761 $content .= 'Content-MD5: '.$_content['md5']."\r\n";
1762 }
1763
1764 $content .= "\r\n".$_content['data']."\r\n";
1765
1766 if (!array_key_exists('image', $this->_msgContent) && $_content['dataText'] && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1767 // Add plain text message part after html part
1768 $content .= "--".$this->_getBoundary('alternative')."--\r\n";
1769 }
1770
1771 $content .= "\r\n";
1772 }
1773 }
1774
1775 $content .= "--".$this->_getBoundary('mixed').'--'."\r\n";
1776 } else {
1777 die("Sorry, no content");
1778 }
1779
1780 return $content;
1781 }
1782
1793 public function setAttachment($strContent, $strFileName = 'unknown', $strMimeType = 'unknown', $strCid = '')
1794 {
1795 if ($strContent) {
1796 $strContent = rtrim(chunk_split(base64_encode($strContent), 76, "\r\n")); // 76 max is defined into http://tools.ietf.org/html/rfc2047
1797
1798 $this->_msgContent['attachment'][$strFileName]['mimeType'] = $strMimeType;
1799 $this->_msgContent['attachment'][$strFileName]['fileName'] = $strFileName;
1800 $this->_msgContent['attachment'][$strFileName]['data'] = $strContent;
1801 $this->_msgContent['attachment'][$strFileName]['cid'] = $strCid; // If defined, it means this attachment must be shown inline
1802
1803 if ($this->getMD5flag()) {
1804 $this->_msgContent['attachment'][$strFileName]['md5'] = dol_hash($strContent, '3');
1805 }
1806 }
1807 }
1808
1809
1810 // @CHANGE LDR
1811
1822 public function setImageInline($strContent, $strImageName = 'unknown', $strMimeType = 'unknown', $strImageCid = 'unknown')
1823 {
1824 if ($strContent) {
1825 $this->_msgContent['image'][$strImageName]['mimeType'] = $strMimeType;
1826 $this->_msgContent['image'][$strImageName]['imageName'] = $strImageName;
1827 $this->_msgContent['image'][$strImageName]['cid'] = $strImageCid;
1828 $this->_msgContent['image'][$strImageName]['data'] = $strContent;
1829
1830 if ($this->getMD5flag()) {
1831 $this->_msgContent['image'][$strImageName]['md5'] = dol_hash($strContent, '3');
1832 }
1833 }
1834 }
1835 // END @CHANGE LDR
1836
1837
1849 public function setSensitivity($_value = 0)
1850 {
1851 if ((is_numeric($_value)) &&
1852 (($_value >= 0) && ($_value <= 3))) {
1853 $this->_msgSensitivity = $_value;
1854 }
1855 }
1856
1867 public function getSensitivity()
1868 {
1869 return $this->_arySensitivity[$this->_msgSensitivity];
1870 }
1871
1885 public function setPriority($_value = 3)
1886 {
1887 if ((is_numeric($_value)) &&
1888 (($_value >= 0) && ($_value <= 5))) {
1889 $this->_msgPriority = $_value;
1890 }
1891 }
1892
1905 public function getPriority()
1906 {
1907 return 'Importance: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1908 . 'Priority: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1909 . 'X-Priority: '.$this->_msgPriority.' ('.$this->_aryPriority[$this->_msgPriority].')'."\r\n";
1910 }
1911
1918 public function setMD5flag($_flag = false)
1919 {
1920 $this->_smtpMD5 = $_flag;
1921 }
1922
1928 public function getMD5flag()
1929 {
1930 return $this->_smtpMD5;
1931 }
1932
1941 public function setXheader($strXdata)
1942 {
1943 if ($strXdata) {
1944 $this->_msgXheader[] = $strXdata;
1945 }
1946 }
1947
1953 public function getXheader()
1954 {
1955 return $this->_msgXheader;
1956 }
1957
1963 private function _setBoundary()
1964 {
1965 $this->_smtpsBoundary = "multipart_x.".time().".x_boundary";
1966 $this->_smtpsRelatedBoundary = 'mul_'.dol_hash(uniqid("dolibarr2"), '3');
1967 $this->_smtpsAlternativeBoundary = 'mul_'.dol_hash(uniqid("dolibarr3"), '3');
1968 }
1969
1976 private function _getBoundary($type = 'mixed')
1977 {
1978 if ($type == 'mixed') {
1979 return $this->_smtpsBoundary;
1980 } elseif ($type == 'related') {
1981 return $this->_smtpsRelatedBoundary;
1982 } elseif ($type == 'alternative') {
1983 return $this->_smtpsAlternativeBoundary;
1984 }
1985 return '';
1986 }
1987
1988 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1999 public function server_parse($socket, $response)
2000 {
2001 // phpcs:enable
2006 $_retVal = true;
2007
2008 $server_response = '';
2009
2010 // avoid infinite loop
2011 $limit = 0;
2012
2013 while (substr($server_response, 3, 1) != ' ' && $limit < 100) {
2014 if (!($server_response = fgets($socket, 256))) {
2015 $this->_setErr(121, "Couldn't get mail server response codes");
2016 $_retVal = false;
2017 break;
2018 }
2019 $this->log .= $server_response;
2020 $limit++;
2021 }
2022
2023 $this->lastretval = substr($server_response, 0, 3);
2024
2025 if (!(substr($server_response, 0, 3) == $response)) {
2026 $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse: ".$server_response);
2027 $_retVal = false;
2028 }
2029
2030 return $_retVal;
2031 }
2032
2033 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2042 public function socket_send_str($_strSend, $_returnCode = null, $CRLF = "\r\n")
2043 {
2044 // phpcs:enable
2045 if ($this->_debug) {
2046 $this->log .= $_strSend; // @CHANGE LDR for log
2047 }
2048 fwrite($this->socket, $_strSend.$CRLF);
2049 if ($this->_debug) {
2050 $this->log .= ' ('.$_returnCode.')'.$CRLF;
2051 }
2052
2053 if ($_returnCode) {
2054 return $this->server_parse($this->socket, $_returnCode);
2055 }
2056
2057 return null;
2058 }
2059
2060 // =============================================================
2061 // ** Error handling methods
2062
2070 private function _setErr($_errNum, $_errMsg)
2071 {
2072 $this->_smtpsErrors[] = array(
2073 'num' => $_errNum,
2074 'msg' => $_errMsg,
2075 );
2076 }
2077
2083 public function getErrors()
2084 {
2085 $_errMsg = array();
2086
2087 if (is_array($this->_smtpsErrors)) {
2088 foreach ($this->_smtpsErrors as $_err => $_info) {
2089 $_errMsg[] = 'Error ['.$_info['num'].']: '.$_info['msg'];
2090 }
2091 }
2092
2093 return implode("\n", $_errMsg);
2094 }
2095}
2096
2097
2098// =============================================================
2099// ** CSV Version Control Info
2100
Class to construct and send SMTP compliant email, even to a secure SMTP server, regardless of platfor...
_getBoundary($type='mixed')
Retrieves the MIME message Boundary.
setConfig($_strConfigPath=null)
setConfig() is used to populate select class properties from either a user defined INI file or the sy...
sendMsg()
Now send the message.
getErrors()
Returns applicative errors codes and messages for Class (not the SMTP error code)
setCharSet($_strCharSet)
Character set used for current message Character set is defaulted to 'iso-8859-1';.
setSubject($_strSubject='')
Message Subject.
getPriority()
Message Content Priority Message Priority values:
setReferences($_strReferences)
Set References in the list of Msg-Id.
getMD5flag()
Gets flag which determines whether to calculate message MD5 checksum.
socket_send_str($_strSend, $_returnCode=null, $CRLF="\r\n")
Send str.
_strip_email($_strAddr)
Returns an array of the various parts of an email address This assumes a well formed address:
getTransEncodeType()
Retrieves the Content-Transfer-Encoding.
setTrackId($_val='')
Set trackid.
setToken($_strToken)
User token for OAUTH2.
setInReplyTo($_strInReplyTo)
Set References in the list of Msg-Id.
buildRCPTlist()
build RECIPIENT List, all addresses who will receive this message
getBodyContent()
Retrieves the Message Content.
_buildAddrList($_type, $_addrList)
Inserts given addresses into structured format.
getInReplyTo()
Retrieves the InReplyTo from which mail we reply to.
setOptions($_options=array())
Set delivery receipt.
_server_connect()
Attempt a connection to mail server.
setBodyContent($strContent, $strType='plain')
Message Content.
server_parse($socket, $response)
This function has been modified as provided by SirSir to allow multiline responses when using SMTP Ex...
setTransportType($_type=0)
Determines the method inwhich the messages are to be sent.
getBCC()
Retrieves the BCC Address[es] inwhich to send mail to.
setAttachment($strContent, $strFileName='unknown', $strMimeType='unknown', $strCid='')
File attachments are added to the content array as sub-arrays, allowing for multiple attachments for ...
_setBoundary()
Generates Random string for MIME message Boundary.
getTo()
Retrieves the TO Address[es] inwhich to send mail to.
setPort($_intPort)
Defines the Port Number of the Mail Server to use The default is 25 This is used only with 'socket' b...
getID()
Retrieves the User Name for authentication on Mail Server.
setBCC($_strBCC)
BCC Address[es] inwhich to send mail to.
setReplyTo($_strReplyTo)
Reply-To Address from which mail will be the reply-to.
getToken()
Retrieves the User token for OAUTH2.
setSensitivity($_value=0)
Message Content Sensitivity Message Sensitivity values:
setCC($_strCC)
CC Address[es] inwhich to send mail to.
setTO($_addrTo)
TO Address[es] inwhich to send mail to.
setTransEncodeType($_strTransEncodeType)
Content-Transfer-Encoding, Defaulted to '0' [ZERO] This can be changed for 2byte characters sets Know...
get_email_list($_which=null)
Returns an array of addresses for a specific type; TO, CC or BCC.
setMD5flag($_flag=false)
Set flag which determines whether to calculate message MD5 checksum.
getCharSet()
Retrieves the Character set used for current message.
getCC()
Retrieves the CC Address[es] inwhich to send mail to.
getDeliveryReceipt()
get delivery receipt
getTrackId()
get trackid
setFrom($_strFrom)
FROM Address from which mail will be sent.
get_RCPT_list()
Returns an array of bare addresses for use with 'RCPT TO:' This is a "build as you go" method.
_server_authenticate()
Attempt mail server authentication for a secure connection.
setID($_strID)
User Name for authentication on Mail Server.
getMoreInHeader()
get moreInHeader
getPW()
Retrieves the User Password for authentication on Mail Server.
getSubject()
Retrieves the Message Subject.
getXheader()
Retrieves the Message X-Header Content.
setErrorsTo($_strErrorsTo)
Set errors to.
setImageInline($strContent, $strImageName='unknown', $strMimeType='unknown', $strImageCid='unknown')
Image attachments are added to the content array as sub-arrays, allowing for multiple images for each...
setHost($_strHost)
Defines the Host Name or IP of the Mail Server to use.
getFrom($_part=true)
Retrieves the Address from which mail will be sent.
getHost()
Retrieves the Host Name or IP of the Mail Server to use This is used only with 'socket' based mail tr...
setPW($_strPW)
User Password for authentication on Mail Server.
getReplyTo($_part=true)
Retrieves the Address from which mail will be the reply-to.
setPriority($_value=3)
Message Content Priority Message Priority values:
setMoreInHeader($_val='')
Set moreInHeader.
getErrorsTo($_part=true)
Get errors to.
getSensitivity()
Returns Message Content Sensitivity string Message Sensitivity values:
getPort()
Retrieves the Port Number of the Mail Server to use This is used only with 'socket' based mail transm...
getTransportType()
Return the method inwhich the message is to be sent.
setMailPath($_path)
Path to the sendmail executable.
getTransEncode()
Retrieves the Content-Transfer-Encoding.
getReferences()
Retrieves the References from which mail will be the reply-to.
setTransEncode($_strTransEncode)
Content-Transfer-Encoding, Defaulted to '7bit' This can be changed for 2byte characters sets Known En...
setDebug($_vDebug=false)
Set debug.
setDeliveryReceipt($_val=0)
Set delivery receipt.
_setErr($_errNum, $_errMsg)
Defines errors codes and messages for Class.
getHeader()
Constructs and returns message header.
setXheader($strXdata)
Message X-Header Content This is a simple "insert".
is_ip($ip)
This function evaluates a string that should be a valid IPv4 Note: For ip 169.254....
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
getDomainFromURL($url, $mode=0)
Function get second level domain name.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.