dolibarr 20.0.0
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 = null;
125
130 private $_smtpsCharSet = 'iso-8859-1';
131
136 private $_msgSensitivity = 0;
137
141 private $_arySensitivity = array(false,
142 'Personal',
143 'Private',
144 'Company Confidential');
145
150 private $_msgPriority = 3;
151
155 private $_aryPriority = array('Bulk',
156 'Highest',
157 'High',
158 'Normal',
159 'Low',
160 'Lowest');
161
167
171 private $_smtpsTransEncodeTypes = array('7bit', // Simple 7-bit ASCII
172 '8bit', // 8-bit coding with line termination characters
173 'base64', // 3 octets encoded into 4 sextets with offset
174 'binary', // Arbitrary binary stream
175 'mac-binhex40', // Macintosh binary to hex encoding
176 'quoted-printable', // Mostly 7-bit, with 8-bit characters encoded as "=HH"
177 'uuencode'); // UUENCODE encoding
178
183 private $_smtpsTransEncode = '7bit';
184
188 private $_smtpsBoundary = null;
189
194
199
207 private $_transportType = 0;
208
213 private $_mailPath = '/usr/lib/sendmail'; // @phpstan-ignore-line
214
218 private $_smtpTimeout = 10;
219
223 private $_smtpMD5 = false;
224
228 private $_smtpsErrors = null;
229
237 private $_log_level = 0; // @phpstan-ignore-line
238
242 private $_debug = false;
243
244
245 // @CHANGE LDR
246 public $log = '';
247 public $lastretval = '';
248
252 public $socket;
253
257 public $errno;
258
262 public $errstr;
263
264 private $_errorsTo = '';
265 private $_deliveryReceipt = 0;
266 private $_trackId = '';
267 private $_moreinheader = '';
268
272 private $_options = array();
273
280 public function setOptions($_options = array())
281 {
282 $this->_options = $_options;
283 }
284
291 public function setDeliveryReceipt($_val = 0)
292 {
293 $this->_deliveryReceipt = $_val;
294 }
295
301 public function getDeliveryReceipt()
302 {
303 return $this->_deliveryReceipt;
304 }
305
312 public function setTrackId($_val = '')
313 {
314 $this->_trackId = $_val;
315 }
316
323 public function setMoreInHeader($_val = '')
324 {
325 $this->_moreinheader = $_val;
326 }
327
333 public function getTrackId()
334 {
335 return $this->_trackId;
336 }
337
343 public function getMoreInHeader()
344 {
345 return $this->_moreinheader;
346 }
347
354 public function setErrorsTo($_strErrorsTo)
355 {
356 if ($_strErrorsTo) {
357 $this->_errorsTo = $this->_strip_email($_strErrorsTo);
358 }
359 }
360
367 public function getErrorsTo($_part = true)
368 {
369 $_retValue = '';
370
371 if ($_part === true) {
372 $_retValue = $this->_errorsTo;
373 } else {
374 $_retValue = $this->_errorsTo[$_part];
375 }
376
377 return $_retValue;
378 }
379
386 public function setDebug($_vDebug = false)
387 {
388 $this->_debug = $_vDebug;
389 }
390
396 public function buildRCPTlist()
397 {
398 // Pull TO list
399 $_aryToList = $this->getTo();
400 }
401
402 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
408 private function _server_connect()
409 {
410 // phpcs:enable
411 // Default return value
412 $_retVal = true;
413
414 // We have to make sure the HOST given is valid
415 // This is done here because '@fsockopen' will not give me this
416 // information if it fails to connect because it can't find the HOST
417 $host = $this->getHost();
418 $usetls = preg_match('@tls://@i', $host);
419
420 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
421 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
422 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
423
424 // @CHANGE LDR
425 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
426
427 if ((!is_ip($host)) && ((gethostbyname($host)) == $host)) {
428 $this->_setErr(99, $host.' is either offline or is an invalid host name.');
429 $_retVal = false;
430 } else {
431 if (function_exists('stream_socket_client') && !empty($this->_options)) {
432 $socket_context = stream_context_create($this->_options); // An array of options for stream_context_create()
433 $this->socket = @stream_socket_client(
434 preg_replace('@tls://@i', '', $this->getHost()).// Host to 'hit', IP or domain
435 ':'.$this->getPort(), // which Port number to use
436 $this->errno, // actual system level error
437 $this->errstr, // and any text that goes with the error
438 $this->_smtpTimeout, // timeout for reading/writing data over the socket
439 STREAM_CLIENT_CONNECT,
440 $socket_context // Options for connection
441 );
442 } else {
443 $this->socket = @fsockopen(
444 preg_replace('@tls://@i', '', $this->getHost()), // Host to 'hit', IP or domain
445 $this->getPort(), // which Port number to use
446 $this->errno, // actual system level error
447 $this->errstr, // and any text that goes with the error
448 $this->_smtpTimeout // timeout for reading/writing data over the socket
449 );
450 }
451
452 //See if we can connect to the SMTP server
453 if (is_resource($this->socket)) {
454 // Fix from PHP SMTP class by 'Chris Ryan'
455 // Sometimes the SMTP server takes a little longer to respond
456 // so we will give it a longer timeout for the first read
457 // Windows still does not have support for this timeout function
458 if (function_exists('stream_set_timeout')) {
459 stream_set_timeout($this->socket, $this->_smtpTimeout, 0);
460 }
461
462 // Check response from Server
463 if ($_retVal = $this->server_parse($this->socket, "220")) {
464 $_retVal = $this->socket;
465 }
466 } else {
467 // This connection attempt failed.
468 // @CHANGE LDR
469 if (empty($this->errstr)) {
470 $this->errstr = 'Failed to connect with fsockopen host='.$this->getHost().' port='.$this->getPort();
471 }
472 $this->_setErr($this->errno, $this->errstr);
473 $_retVal = false;
474 }
475 }
476
477 return $_retVal;
478 }
479
480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
486 private function _server_authenticate()
487 {
488 // phpcs:enable
489 global $conf;
490
491 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
492 // Send the RFC2554 specified EHLO.
493 // This improvement as provided by 'SirSir' to
494 // accommodate both SMTP AND ESMTP capable servers
495 $host = $this->getHost();
496 $usetls = preg_match('@tls://@i', $host);
497
498 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
499 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
500 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
501
502 if ($usetls && getDolGlobalString('MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO')) {
503 $host = 'tls://'.$host;
504 }
505
506 $hosth = $host; // so for example 'localhost' or 'smtp-relay.gmail.com'
507
508 if (getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO')) {
509 if (!is_numeric(getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO'))) {
510 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
511 $hosth = getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO');
512 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 1) {
513 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
514 // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
515 $hosth = $this->getFrom('addr');
516 $hosth = preg_replace('/^.*</', '', $hosth);
517 $hosth = preg_replace('/>.*$/', '', $hosth);
518 $hosth = preg_replace('/.*@/', '', $hosth);
519 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 2) {
520 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
521 global $dolibarr_main_url_root;
522 $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
523 }
524 }
525
526 if ($_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
527 if ($usetls) {
528 /*
529 The following dialog illustrates how a client and server can start a TLS STARTTLS session:
530 S: <waits for connection on TCP port 25>
531 C: <opens connection>
532 S: 220 mail.imc.org SMTP service ready
533 C: EHLO mail.ietf.org
534 S: 250-mail.imc.org offers a warm hug of welcome
535 S: 250 STARTTLS
536 C: STARTTLS
537 S: 220 Go ahead
538 C: <starts TLS negotiation>
539 C & S: <negotiate a TLS session>
540 C & S: <check result of negotiation>
541 // Second pass EHLO
542 C: EHLO client-domain.com
543 S: 250-server-domain.com
544 S: 250 AUTH LOGIN
545 C: <continues by sending an SMTP command
546
547 Another example here:
548 S: 220 smtp.server.com Simple Mail Transfer Service Ready
549 C: EHLO client.example.com
550 S: 250-smtp.server.com Hello client.example.com
551 S: 250-SIZE 1000000
552 S: 250-AUTH LOGIN PLAIN CRAM-MD5
553 S: 250-STARTTLS
554 S: 250 HELP
555 C: STARTTLS
556 S: 220 TLS go ahead
557 C: EHLO client.example.com *
558 S: 250-smtp.server.com Hello client.example.com
559 S: 250-SIZE 1000000
560 S: 250-AUTH LOGIN PLAIN CRAM-MD5
561 S: 250 HELP
562 C: AUTH LOGIN
563 S: 334 VXNlcm5hbWU6
564 C: adlxdkej
565 S: 334 UGFzc3dvcmQ6
566 C: lkujsefxlj
567 S: 235 2.7.0 Authentication successful
568 C: MAIL FROM:<mail@samlogic.com>
569 S: 250 OK
570 C: RCPT TO:<john@mail.com>
571 S: 250 OK
572 C: DATA
573 S: 354 Send message, end with a "." on a line by itself
574 C: <The message data (body text, subject, e-mail header, attachments etc) is sent>
575 S .
576 S: 250 OK, message accepted for delivery: queued as 12345
577 C: QUIT
578 S: 221 Bye
579 */
580 if (!$_retVal = $this->socket_send_str('STARTTLS', 220)) {
581 $this->_setErr(131, 'STARTTLS connection is not supported.');
582 return $_retVal;
583 }
584
585 // Before 5.6.7:
586 // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_SSLv2_CLIENT|STREAM_CRYPTO_METHOD_SSLv3_CLIENT
587 // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
588 // PHP >= 5.6.7:
589 // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
590 // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
591
592 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
593 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
594 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
595 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
596 }
597
598 if (!stream_socket_enable_crypto($this->socket, true, $crypto_method)) {
599 $this->_setErr(132, 'STARTTLS connection failed.');
600 return $_retVal;
601 }
602 // Most servers expect a 2nd pass of EHLO after TLS is established to get another time
603 // the answer with list of supported AUTH methods. They may differs between non STARTTLS and with STARTTLS.
604 if (! $_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
605 $this->_setErr(126, '"'.$hosth.'" does not support authenticated connections or temporary error. Error after 2nd sending EHLO '.$hosth.' : '.$this->lastretval);
606 return $_retVal;
607 }
608 }
609
610 // Default authentication method is LOGIN
611 if (!getDolGlobalString('MAIN_MAIL_SMTPS_AUTH_TYPE')) {
612 $conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE = 'LOGIN';
613 }
614
615 // Send Authentication to Server
616 // Check for errors along the way
617 switch ($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE) {
618 case 'NONE':
619 // 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.
620 $_retVal = true;
621 break;
622 case 'PLAIN':
623 $this->socket_send_str('AUTH PLAIN', '334');
624 // The error here just means the ID/password combo doesn't work.
625 $_retVal = $this->socket_send_str(base64_encode("\0".$this->_smtpsID."\0".$this->_smtpsPW), '235');
626 break;
627 case 'XOAUTH2':
628 // "user=$email\1auth=Bearer $token\1\1"
629 $user = $this->_smtpsID;
630 $token = $this->_smtpsToken;
631 $initRes = "user=".$user."\001auth=Bearer ".$token."\001\001";
632 $_retVal = $this->socket_send_str('AUTH XOAUTH2 '.base64_encode($initRes), '235');
633 if (!$_retVal) {
634 $this->_setErr(130, 'Error when asking for AUTH XOAUTH2');
635 }
636 break;
637 case 'LOGIN': // most common case
638 default:
639 $_retVal = $this->socket_send_str('AUTH LOGIN', '334');
640 if (!$_retVal) {
641 $this->_setErr(130, 'Error when asking for AUTH LOGIN');
642 } else {
643 // User name will not return any error, server will take anything we give it.
644 $this->socket_send_str(base64_encode($this->_smtpsID), '334');
645 // The error here just means the ID/password combo doesn't work.
646 // There is no method to determine which is the problem, ID or password
647 $_retVal = $this->socket_send_str(base64_encode($this->_smtpsPW), '235');
648 }
649 break;
650 }
651 if (!$_retVal) {
652 $this->_setErr(130, 'Invalid Authentication Credentials.');
653 }
654 } else {
655 $this->_setErr(126, '"'.$host.'" does not support authenticated connections or temporary error. Error after sending EHLO '.$hosth.' : '.$this->lastretval);
656 }
657
658 return $_retVal;
659 }
660
666 public function sendMsg()
667 {
668 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
669
670 // Default return value
671 $_retVal = false;
672
673 // Connect to Server
674 if ($this->socket = $this->_server_connect()) {
675 // If a User ID *and* a password is given, assume Authentication is desired
676 if (!empty($this->_smtpsID) && (!empty($this->_smtpsPW) || !empty($this->_smtpsToken))) {
677 // Send the RFC2554 specified EHLO.
678 $_retVal = $this->_server_authenticate();
679 } else {
680 // This is a "normal" SMTP Server "handshack"
681 // Send the RFC821 specified HELO.
682 $host = $this->getHost();
683 $usetls = preg_match('@tls://@i', $host);
684
685 $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
686 $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
687 $host = preg_replace('@tls://@i', '', $host); // Remove prefix
688
689 if ($usetls && getDolGlobalString('MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO')) {
690 $host = 'tls://'.$host;
691 }
692
693 $hosth = $host;
694
695 if (getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO')) {
696 if (!is_numeric(getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO'))) {
697 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
698 $hosth = getDolGlobalString('MAIL_SMTP_USE_FROM_FOR_HELO');
699 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 1) {
700 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
701 // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
702 $hosth = $this->getFrom('addr');
703 $hosth = preg_replace('/^.*</', '', $hosth);
704 $hosth = preg_replace('/>.*$/', '', $hosth);
705 $hosth = preg_replace('/.*@/', '', $hosth);
706 } elseif (getDolGlobalInt('MAIL_SMTP_USE_FROM_FOR_HELO') == 2) {
707 // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
708 global $dolibarr_main_url_root;
709 $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
710 }
711 }
712
713 // Send the HELO message to the SMTP server
714 $_retVal = $this->socket_send_str('HELO '.$hosth, '250');
715 }
716
717 // Well, did we get the server answer with correct code ?
718 if ($_retVal) {
719 // From this point onward most server response codes should be 250
720 // Specify who the mail is from....
721 // This has to be the raw email address, strip the "name" off
722 $resultmailfrom = $this->socket_send_str('MAIL FROM: '.$this->getFrom('addr'), '250');
723 if (!$resultmailfrom) {
724 fclose($this->socket);
725 return false;
726 }
727
728 // 'RCPT TO:' must be given a single address, so this has to loop
729 // through the list of addresses, regardless of TO, CC or BCC
730 // and send it out "single file"
731 foreach ($this->get_RCPT_list() as $_address) {
732 /* Note:
733 * BCC email addresses must be listed in the RCPT TO command list,
734 * but the BCC header should not be printed under the DATA command.
735 * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
736 */
737
738 /*
739 * TODO
740 * After each 'RCPT TO:' is sent, we need to make sure it was kosher,
741 * if not, the whole message will fail
742 * If any email address fails, we will need to RESET the connection,
743 * mark the last address as "bad" and start the address loop over again.
744 * If any address fails, the entire message fails.
745 */
746 $this->socket_send_str('RCPT TO: <'.$_address.'>', '250');
747 }
748
749 // Tell the server we are ready to start sending data
750 // with any custom headers...
751 // This is the last response code we look for until the end of the message.
752 $this->socket_send_str('DATA', '354');
753
754 // Now we are ready for the message...
755 // Ok, all the ingredients are mixed in let's cook this puppy...
756 $this->socket_send_str($this->getHeader().$this->getBodyContent()."\r\n".'.', '250');
757
758 // Now tell the server we are done and close the socket...
759 fwrite($this->socket, 'QUIT');
760 } else {
761 // We got error code into $this->lastretval
762 }
763
764 fclose($this->socket);
765 }
766
767 return $_retVal;
768 }
769
770 // =============================================================
771 // ** Setter & Getter methods
772
773 // ** Basic System configuration
774
800 public function setConfig($_strConfigPath = null)
801 {
806 $_retVal = true;
807
808 // if we have a path...
809 if (!empty($_strConfigPath)) {
810 // If the path is not valid, this will NOT generate an error,
811 // it will simply return false.
812 if (!@include $_strConfigPath) {
813 $this->_setErr(110, '"'.$_strConfigPath.'" is not a valid path.');
814 $_retVal = false;
815 }
816 } else {
817 // Read the Systems php.ini file
818 // Set these properties ONLY if they are set in the php.ini file.
819 // Otherwise the default values will be used.
820 if ($_host = ini_get('SMTPs')) {
821 $this->setHost($_host);
822 }
823
824 if ($_port = ini_get('smtp_port')) {
825 $this->setPort($_port);
826 }
827
828 if ($_from = ini_get('sendmail_from')) {
829 $this->setFrom($_from);
830 }
831 }
832
833 // Send back what we have
834 return $_retVal;
835 }
836
846 public function setTransportType($_type = 0)
847 {
848 if ((is_numeric($_type)) && (($_type >= 0) && ($_type <= 3))) {
849 $this->_transportType = $_type;
850 }
851 }
852
861 public function getTransportType()
862 {
864 }
865
873 public function setMailPath($_path)
874 {
875 // This feature is not yet implemented
876 return true;
877
878 //if ( $_path ) $this->_mailPath = $_path;
879 }
880
889 public function setHost($_strHost)
890 {
891 if ($_strHost) {
892 $this->_smtpsHost = $_strHost;
893 }
894 }
895
902 public function getHost()
903 {
904 return $this->_smtpsHost;
905 }
906
915 public function setPort($_intPort)
916 {
917 if ((is_numeric($_intPort)) &&
918 (($_intPort >= 1) && ($_intPort <= 65536))) {
919 $this->_smtpsPort = (int) $_intPort;
920 }
921 }
922
929 public function getPort()
930 {
931 return (int) $this->_smtpsPort;
932 }
933
940 public function setID($_strID)
941 {
942 $this->_smtpsID = $_strID;
943 }
944
950 public function getID()
951 {
952 return $this->_smtpsID;
953 }
954
961 public function setPW($_strPW)
962 {
963 $this->_smtpsPW = $_strPW;
964 }
965
971 public function getPW()
972 {
973 return $this->_smtpsPW;
974 }
975
982 public function setToken($_strToken)
983 {
984 $this->_smtpsToken = $_strToken;
985 }
986
992 public function getToken()
993 {
994 return $this->_smtpsToken;
995 }
996
1004 public function setCharSet($_strCharSet)
1005 {
1006 if ($_strCharSet) {
1007 $this->_smtpsCharSet = $_strCharSet;
1008 }
1009 }
1010
1016 public function getCharSet()
1017 {
1018 return $this->_smtpsCharSet;
1019 }
1020
1036 public function setTransEncode($_strTransEncode)
1037 {
1038 if (array_search($_strTransEncode, $this->_smtpsTransEncodeTypes)) {
1039 $this->_smtpsTransEncode = $_strTransEncode;
1040 }
1041 }
1042
1048 public function getTransEncode()
1049 {
1051 }
1052
1069 public function setTransEncodeType($_strTransEncodeType)
1070 {
1071 if (array_search($_strTransEncodeType, $this->_smtpsTransEncodeTypes)) {
1072 $this->_smtpsTransEncodeType = $_strTransEncodeType;
1073 }
1074 }
1075
1081 public function getTransEncodeType()
1082 {
1083 return $this->_smtpsTransEncodeTypes[$this->_smtpsTransEncodeType];
1084 }
1085
1086
1087 // ** Message Construction
1088
1095 public function setFrom($_strFrom)
1096 {
1097 if ($_strFrom) {
1098 $this->_msgFrom = $this->_strip_email($_strFrom);
1099 }
1100 }
1101
1108 public function getFrom($_part = true)
1109 {
1110 $_retValue = '';
1111
1112 if ($_part === true) {
1113 $_retValue = $this->_msgFrom;
1114 } else {
1115 $_retValue = $this->_msgFrom[$_part];
1116 }
1117
1118 return $_retValue;
1119 }
1120
1127 public function setReplyTo($_strReplyTo)
1128 {
1129 if ($_strReplyTo) {
1130 $this->_msgReplyTo = $this->_strip_email($_strReplyTo);
1131 }
1132 }
1133
1140 public function getReplyTo($_part = true)
1141 {
1142 $_retValue = '';
1143
1144 if ($_part === true) {
1145 $_retValue = $this->_msgReplyTo;
1146 } else {
1147 $_retValue = $this->_msgReplyTo[$_part];
1148 }
1149
1150 return $_retValue;
1151 }
1152
1159 public function setInReplyTo($_strInReplyTo)
1160 {
1161 if ($_strInReplyTo) {
1162 $this->_msgInReplyTo = $_strInReplyTo;
1163 }
1164 }
1165
1171 public function getInReplyTo()
1172 {
1173 $_retValue = $this->_msgInReplyTo;
1174
1175 return $_retValue;
1176 }
1177
1184 public function setReferences($_strReferences)
1185 {
1186 if ($_strReferences) {
1187 $this->_msgReferences = $_strReferences;
1188 }
1189 }
1190
1196 public function getReferences()
1197 {
1198 $_retValue = $this->_msgReferences;
1199
1200 return $_retValue;
1201 }
1202
1213 private function _buildAddrList($_type, $_addrList)
1214 {
1215 // Pull existing list
1216 $aryHost = $this->_msgRecipients;
1217
1218 // Only run this if we have something
1219 if (!empty($_addrList)) {
1220 // $_addrList can be a STRING or an array
1221 if (is_string($_addrList)) {
1222 // This could be a COMMA delimited string
1223 if (strstr($_addrList, ',')) {
1224 // "explode "list" into an array
1225 $_addrList = explode(',', $_addrList);
1226 } else {
1227 // Stick it in an array
1228 $_addrList = array($_addrList);
1229 }
1230 }
1231
1232 // take the array of addresses and split them further
1233 foreach ($_addrList as $_strAddr) {
1234 // Strip off the end '>'
1235 $_strAddr = str_replace('>', '', $_strAddr);
1236
1237 // Separate "Real Name" from eMail address
1238 $_tmpaddr = null;
1239 $_tmpaddr = explode('<', $_strAddr);
1240
1241 // We have a "Real Name" and eMail address
1242 if (count($_tmpaddr) == 2) {
1243 $_tmpHost = explode('@', $_tmpaddr[1]);
1244 $_tmpaddr[0] = trim($_tmpaddr[0], ' ">');
1245 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = $_tmpaddr[0];
1246 } else {
1247 // We only have an eMail address
1248 // Strip off the beginning '<'
1249 $_strAddr = str_replace('<', '', $_strAddr);
1250
1251 $_tmpHost = explode('@', $_strAddr);
1252 $_tmpHost[0] = trim($_tmpHost[0]);
1253 $_tmpHost[1] = trim($_tmpHost[1]);
1254
1255 $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = '';
1256 }
1257 }
1258 }
1259 // replace list
1260 $this->_msgRecipients = $aryHost;
1261 }
1262
1263 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1280 private function _strip_email($_strAddr)
1281 {
1282 // phpcs:enable
1283 $_aryEmail = array();
1284 // Keep the original
1285 $_aryEmail['org'] = $_strAddr;
1286
1287 // Set entire string to Lower Case
1288 $_strAddr = strtolower($_strAddr);
1289
1290 // Drop "stuff' off the end
1291 $_strAddr = trim($_strAddr, ' ">');
1292
1293 // Separate "Real Name" from eMail address, if we have one
1294 $_tmpAry = explode('<', $_strAddr);
1295
1296 // Do we have a "Real name"
1297 if (count($_tmpAry) == 2) {
1298 // We may not really have a "Real Name"
1299 if ($_tmpAry[0]) {
1300 $_aryEmail['real'] = trim($_tmpAry[0], ' ">');
1301 }
1302
1303 $_aryEmail['addr'] = $_tmpAry[1];
1304 } else {
1305 $_aryEmail['addr'] = $_tmpAry[0];
1306 }
1307
1308 // Pull User Name and Host.tld apart
1309 $_tmpHost = explode('@', $_aryEmail['addr']);
1310 $_aryEmail['user'] = $_tmpHost[0];
1311 $_aryEmail['host'] = $_tmpHost[1];
1312
1313 // Put the brackets back around the address
1314 $_aryEmail['addr'] = '<'.$_aryEmail['addr'].'>';
1315
1316 return $_aryEmail;
1317 }
1318
1319 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1327 public function get_RCPT_list()
1328 {
1329 // phpcs:enable
1333 $_RCPT_list = array();
1334
1335 // walk down Recipients array and pull just email addresses
1336 foreach ($this->_msgRecipients as $_host => $_list) {
1337 foreach ($_list as $_subList) {
1338 foreach ($_subList as $_name => $_addr) {
1339 // build RCPT list
1340 $_RCPT_list[] = $_name.'@'.$_host;
1341 }
1342 }
1343 }
1344
1345 return $_RCPT_list;
1346 }
1347
1348 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1355 public function get_email_list($_which = null)
1356 {
1357 // phpcs:enable
1358 // We need to know which address segment to pull
1359 if ($_which) {
1360 // Make sure we have addresses to process
1361 if ($this->_msgRecipients) {
1362 $_RCPT_list = array();
1363 // walk down Recipients array and pull just email addresses
1364 foreach ($this->_msgRecipients as $_host => $_list) {
1365 if (!empty($this->_msgRecipients[$_host][$_which])) {
1366 foreach ($this->_msgRecipients[$_host][$_which] as $_addr => $_realName) {
1367 if ($_realName) { // @CHANGE LDR
1368 $_realName = '"'.$_realName.'"';
1369 $_RCPT_list[] = $_realName.' <'.$_addr.'@'.$_host.'>';
1370 } else {
1371 $_RCPT_list[] = $_addr.'@'.$_host;
1372 }
1373 }
1374 }
1375 }
1376
1377 return implode(', ', $_RCPT_list);
1378 } else {
1379 $this->_setErr(101, 'No eMail Address for message to be sent to.');
1380 return false;
1381 }
1382 } else {
1383 $this->_setErr(102, 'eMail type not defined.');
1384 return false;
1385 }
1386 }
1387
1394 public function setTO($_addrTo)
1395 {
1396 if ($_addrTo) {
1397 $this->_buildAddrList('to', $_addrTo);
1398 }
1399 }
1400
1406 public function getTo()
1407 {
1408 return $this->get_email_list('to');
1409 }
1410
1417 public function setCC($_strCC)
1418 {
1419 if ($_strCC) {
1420 $this->_buildAddrList('cc', $_strCC);
1421 }
1422 }
1423
1429 public function getCC()
1430 {
1431 return $this->get_email_list('cc');
1432 }
1433
1440 public function setBCC($_strBCC)
1441 {
1442 if ($_strBCC) {
1443 $this->_buildAddrList('bcc', $_strBCC);
1444 }
1445 }
1446
1452 public function getBCC()
1453 {
1454 return $this->get_email_list('bcc');
1455 }
1456
1463 public function setSubject($_strSubject = '')
1464 {
1465 if ($_strSubject) {
1466 $this->_msgSubject = $_strSubject;
1467 }
1468 }
1469
1475 public function getSubject()
1476 {
1477 return $this->_msgSubject;
1478 }
1479
1485 public function getHeader()
1486 {
1487 global $conf;
1488
1489 $_header = 'From: '.$this->getFrom('org')."\r\n"
1490 . 'To: '.$this->getTo()."\r\n";
1491
1492 if ($this->getCC()) {
1493 $_header .= 'Cc: '.$this->getCC()."\r\n";
1494 }
1495
1496 /* Note:
1497 * BCC email addresses must be listed in the RCPT TO command list,
1498 * but the BCC header should not be printed under the DATA command.
1499 * So it is included into the function sendMsg() but not here.
1500 * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
1501 */
1502 /*
1503 if ( $this->getBCC() )
1504 $_header .= 'Bcc: ' . $this->getBCC() . "\r\n";
1505 */
1506
1507 $host = dol_getprefix('email');
1508
1509 //NOTE: Message-ID should probably contain the username of the user who sent the msg
1510 $_header .= 'Subject: '.$this->getSubject()."\r\n";
1511 $_header .= 'Date: '.date("r")."\r\n";
1512
1513 $trackid = $this->getTrackId();
1514 if ($trackid) {
1515 $_header .= 'Message-ID: <'.time().'.SMTPs-dolibarr-'.$trackid.'@'.$host.">\r\n";
1516 $_header .= 'X-Dolibarr-TRACKID: '.$trackid.'@'.$host."\r\n";
1517 } else {
1518 $_header .= 'Message-ID: <'.time().'.SMTPs@'.$host.">\r\n";
1519 }
1520 if (!empty($_SERVER['REMOTE_ADDR'])) {
1521 $_header .= "X-RemoteAddr: ".$_SERVER['REMOTE_ADDR']."\r\n";
1522 }
1523 if ($this->getMoreInHeader()) {
1524 $_header .= $this->getMoreInHeader(); // Value must include the "\r\n";
1525 }
1526
1527 if ($this->getSensitivity()) {
1528 $_header .= 'Sensitivity: '.$this->getSensitivity()."\r\n";
1529 }
1530
1531 if ($this->_msgPriority != 3) {
1532 $_header .= $this->getPriority();
1533 }
1534
1535
1536 // @CHANGE LDR
1537 if ($this->getDeliveryReceipt()) {
1538 $_header .= 'Disposition-Notification-To: '.$this->getFrom('addr')."\r\n";
1539 }
1540 if ($this->getErrorsTo()) {
1541 $_header .= 'Errors-To: '.$this->getErrorsTo('addr')."\r\n";
1542 }
1543 if ($this->getReplyTo()) {
1544 $_header .= "Reply-To: ".$this->getReplyTo('addr')."\r\n";
1545 }
1546
1547 $_header .= 'X-Mailer: Dolibarr version '.DOL_VERSION.' (using SMTPs Mailer)'."\r\n";
1548 $_header .= 'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART ? 'MAIN_MAIL_USE_MULTI_PART' : 'No MAIN_MAIL_USE_MULTI_PART')."\r\n";
1549 $_header .= 'Mime-Version: 1.0'."\r\n";
1550
1551 // Add also $this->references and In-Reply-To
1552 if ($this->getInReplyTo()) {
1553 $_header .= "In-Reply-To: ".$this->getInReplyTo()."\r\n";
1554 }
1555 if ($this->getReferences()) {
1556 $_header .= "References: ".$this->getReferences()."\r\n";
1557 }
1558
1559 return $_header;
1560 }
1561
1569 public function setBodyContent($strContent, $strType = 'plain')
1570 {
1571 //if ( $strContent )
1572 //{
1573 if ($strType == 'html') {
1574 $strMimeType = 'text/html';
1575 } else {
1576 $strMimeType = 'text/plain';
1577 }
1578
1579 // Make RFC821 Compliant, replace bare linefeeds
1580 $strContent = preg_replace("/(?<!\r)\n/si", "\r\n", $strContent);
1581
1582 $strContentAltText = '';
1583 if ($strType == 'html') {
1584 // Similar code to forge a text from html is also in CMailFile.class.php
1585 $strContentAltText = preg_replace('/<head><title>.*<\/style><\/head>/', '', $strContent);
1586 $strContentAltText = preg_replace("/<br\s*[^>]*>/", " ", $strContentAltText);
1587 $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1588 $strContentAltText = trim(wordwrap($strContentAltText, 75, "\r\n"));
1589 }
1590
1591 // Make RFC2045 Compliant
1592 //$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
1593 $strContent = rtrim(wordwrap($strContent, 75, "\r\n")); // TODO Using this method creates unexpected line break on text/plain content.
1594
1595 $this->_msgContent[$strType] = array();
1596
1597 $this->_msgContent[$strType]['mimeType'] = $strMimeType;
1598 $this->_msgContent[$strType]['data'] = $strContent;
1599 $this->_msgContent[$strType]['dataText'] = $strContentAltText;
1600
1601 if ($this->getMD5flag()) {
1602 $this->_msgContent[$strType]['md5'] = dol_hash($strContent, 3);
1603 }
1604 //}
1605 }
1606
1612 public function getBodyContent()
1613 {
1614 global $conf;
1615
1616 // Generate a new Boundary string
1617 $this->_setBoundary();
1618
1619 // What type[s] of content do we have
1620 $_types = array_keys($this->_msgContent);
1621
1622 // How many content types do we have
1623 $keyCount = count($_types);
1624
1625 // If we have ZERO, we have a problem
1626 if ($keyCount === 0) {
1627 die("Sorry, no content");
1628 } elseif ($keyCount === 1 && !getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1629 // If we have ONE, we can use the simple format
1630 $_msgData = $this->_msgContent;
1631 $_msgData = $_msgData[$_types[0]];
1632
1633 $content = 'Content-Type: '.$_msgData['mimeType'].'; charset="'.$this->getCharSet().'"'."\r\n"
1634 . 'Content-Transfer-Encoding: '.$this->getTransEncodeType()."\r\n"
1635 . 'Content-Disposition: inline'."\r\n"
1636 . 'Content-Description: Message'."\r\n";
1637
1638 if ($this->getMD5flag()) {
1639 $content .= 'Content-MD5: '.$_msgData['md5']."\r\n";
1640 }
1641
1642 $content .= "\r\n"
1643 . $_msgData['data']."\r\n";
1644 } elseif ($keyCount >= 1 || getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1645 // If we have more than ONE, we use the multi-part format
1646 // Since this is an actual multi-part message
1647 // We need to define a content message Boundary
1648 // NOTE: This was 'multipart/alternative', but Windows based mail servers have issues with this.
1649
1650 //$content = 'Content-Type: multipart/related; boundary="' . $this->_getBoundary() . '"' . "\r\n";
1651 $content = 'Content-Type: multipart/mixed; boundary="'.$this->_getBoundary('mixed').'"'."\r\n";
1652
1653 // . "\r\n"
1654 // . 'This is a multi-part message in MIME format.' . "\r\n";
1655 $content .= "Content-Transfer-Encoding: 8bit\r\n";
1656 $content .= "\r\n";
1657
1658 $content .= "--".$this->_getBoundary('mixed')."\r\n";
1659
1660 if (array_key_exists('image', $this->_msgContent)) { // If inline image found
1661 $content .= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"'."\r\n";
1662 $content .= "\r\n";
1663 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1664 }
1665
1666
1667 // $this->_msgContent must be sorted with key 'text' or 'html' first then 'image' then 'attachment'
1668
1669
1670 // Loop through message content array
1671 foreach ($this->_msgContent as $type => $_content) {
1672 if ($type == 'attachment') {
1673 // loop through all attachments
1674 foreach ($_content as $_file => $_data) {
1675 $content .= "--".$this->_getBoundary('mixed')."\r\n"
1676 . 'Content-Disposition: attachment; filename="'.$_data['fileName'].'"'."\r\n"
1677 . 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['fileName'].'"'."\r\n"
1678 . 'Content-Transfer-Encoding: base64'."\r\n"
1679 . 'Content-Description: '.$_data['fileName']."\r\n";
1680 if (!empty($_data['cid'])) {
1681 $content .= "X-Attachment-Id: ".$_data['cid']."\r\n";
1682 $content .= "Content-ID: <".$_data['cid'].">\r\n";
1683 }
1684 if ($this->getMD5flag()) {
1685 $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1686 }
1687
1688 $content .= "\r\n".$_data['data']."\r\n\r\n";
1689 }
1690 } elseif ($type == 'image') {
1691 // @CHANGE LDR
1692 // loop through all images
1693 foreach ($_content as $_image => $_data) {
1694 $content .= "--".$this->_getBoundary('related')."\r\n"; // always related for an inline image
1695
1696 $content .= 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['imageName'].'"'."\r\n"
1697 . 'Content-Transfer-Encoding: base64'."\r\n"
1698 . 'Content-Disposition: inline; filename="'.$_data['imageName'].'"'."\r\n"
1699 . 'Content-ID: <'.$_data['cid'].'> '."\r\n";
1700
1701 if ($this->getMD5flag()) {
1702 $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1703 }
1704
1705 $content .= "\r\n"
1706 . $_data['data']."\r\n";
1707 }
1708
1709 // always end related and end alternative after inline images
1710 $content .= "--".$this->_getBoundary('related')."--\r\n";
1711 $content .= "\r\n--".$this->_getBoundary('alternative')."--\r\n";
1712 $content .= "\r\n";
1713 } else {
1714 if (array_key_exists('image', $this->_msgContent)) {
1715 $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1716 $content .= "\r\n".($_content['dataText'] ? $_content['dataText'] : strip_tags($_content['data']))."\r\n"; // Add plain text message
1717 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1718 $content .= 'Content-Type: multipart/related; boundary="'.$this->_getBoundary('related').'"'."\r\n";
1719 $content .= "\r\n";
1720 $content .= "--".$this->_getBoundary('related')."\r\n";
1721 }
1722
1723 if (!array_key_exists('image', $this->_msgContent) && $_content['dataText'] && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1724 // Add plain text message part before html part
1725 $content .= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"'."\r\n";
1726 $content .= "\r\n";
1727 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1728
1729 $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1730 $content .= "\r\n".$_content['dataText']."\r\n";
1731 $content .= "--".$this->_getBoundary('alternative')."\r\n";
1732 }
1733
1734 $content .= 'Content-Type: '.$_content['mimeType'].'; charset='.$this->getCharSet();
1735
1736 $content .= "\r\n";
1737
1738 if ($this->getMD5flag()) {
1739 $content .= 'Content-MD5: '.$_content['md5']."\r\n";
1740 }
1741
1742 $content .= "\r\n".$_content['data']."\r\n";
1743
1744 if (!array_key_exists('image', $this->_msgContent) && $_content['dataText'] && getDolGlobalString('MAIN_MAIL_USE_MULTI_PART')) {
1745 // Add plain text message part after html part
1746 $content .= "--".$this->_getBoundary('alternative')."--\r\n";
1747 }
1748
1749 $content .= "\r\n";
1750 }
1751 }
1752
1753 $content .= "--".$this->_getBoundary('mixed').'--'."\r\n";
1754 } else {
1755 die("Sorry, no content");
1756 }
1757
1758 return $content;
1759 }
1760
1771 public function setAttachment($strContent, $strFileName = 'unknown', $strMimeType = 'unknown', $strCid = '')
1772 {
1773 if ($strContent) {
1774 $strContent = rtrim(chunk_split(base64_encode($strContent), 76, "\r\n")); // 76 max is defined into http://tools.ietf.org/html/rfc2047
1775
1776 $this->_msgContent['attachment'][$strFileName]['mimeType'] = $strMimeType;
1777 $this->_msgContent['attachment'][$strFileName]['fileName'] = $strFileName;
1778 $this->_msgContent['attachment'][$strFileName]['data'] = $strContent;
1779 $this->_msgContent['attachment'][$strFileName]['cid'] = $strCid; // If defined, it means this attachment must be shown inline
1780
1781 if ($this->getMD5flag()) {
1782 $this->_msgContent['attachment'][$strFileName]['md5'] = dol_hash($strContent, 3);
1783 }
1784 }
1785 }
1786
1787
1788 // @CHANGE LDR
1789
1800 public function setImageInline($strContent, $strImageName = 'unknown', $strMimeType = 'unknown', $strImageCid = 'unknown')
1801 {
1802 if ($strContent) {
1803 $this->_msgContent['image'][$strImageName]['mimeType'] = $strMimeType;
1804 $this->_msgContent['image'][$strImageName]['imageName'] = $strImageName;
1805 $this->_msgContent['image'][$strImageName]['cid'] = $strImageCid;
1806 $this->_msgContent['image'][$strImageName]['data'] = $strContent;
1807
1808 if ($this->getMD5flag()) {
1809 $this->_msgContent['image'][$strImageName]['md5'] = dol_hash($strContent, 3);
1810 }
1811 }
1812 }
1813 // END @CHANGE LDR
1814
1815
1827 public function setSensitivity($_value = 0)
1828 {
1829 if ((is_numeric($_value)) &&
1830 (($_value >= 0) && ($_value <= 3))) {
1831 $this->_msgSensitivity = $_value;
1832 }
1833 }
1834
1845 public function getSensitivity()
1846 {
1847 return $this->_arySensitivity[$this->_msgSensitivity];
1848 }
1849
1863 public function setPriority($_value = 3)
1864 {
1865 if ((is_numeric($_value)) &&
1866 (($_value >= 0) && ($_value <= 5))) {
1867 $this->_msgPriority = $_value;
1868 }
1869 }
1870
1883 public function getPriority()
1884 {
1885 return 'Importance: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1886 . 'Priority: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1887 . 'X-Priority: '.$this->_msgPriority.' ('.$this->_aryPriority[$this->_msgPriority].')'."\r\n";
1888 }
1889
1896 public function setMD5flag($_flag = false)
1897 {
1898 $this->_smtpMD5 = $_flag;
1899 }
1900
1906 public function getMD5flag()
1907 {
1908 return $this->_smtpMD5;
1909 }
1910
1919 public function setXheader($strXdata)
1920 {
1921 if ($strXdata) {
1922 $this->_msgXheader[] = $strXdata;
1923 }
1924 }
1925
1931 public function getXheader()
1932 {
1933 return $this->_msgXheader;
1934 }
1935
1941 private function _setBoundary()
1942 {
1943 $this->_smtpsBoundary = "multipart_x.".time().".x_boundary";
1944 $this->_smtpsRelatedBoundary = 'mul_'.dol_hash(uniqid("dolibarr2"), 3);
1945 $this->_smtpsAlternativeBoundary = 'mul_'.dol_hash(uniqid("dolibarr3"), 3);
1946 }
1947
1954 private function _getBoundary($type = 'mixed')
1955 {
1956 if ($type == 'mixed') {
1957 return $this->_smtpsBoundary;
1958 } elseif ($type == 'related') {
1960 } elseif ($type == 'alternative') {
1962 }
1963 return '';
1964 }
1965
1966 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1977 public function server_parse($socket, $response)
1978 {
1979 // phpcs:enable
1984 $_retVal = true;
1985
1986 $server_response = '';
1987
1988 // avoid infinite loop
1989 $limit = 0;
1990
1991 while (substr($server_response, 3, 1) != ' ' && $limit < 100) {
1992 if (!($server_response = fgets($socket, 256))) {
1993 $this->_setErr(121, "Couldn't get mail server response codes");
1994 $_retVal = false;
1995 break;
1996 }
1997 $this->log .= $server_response;
1998 $limit++;
1999 }
2000
2001 $this->lastretval = substr($server_response, 0, 3);
2002
2003 if (!(substr($server_response, 0, 3) == $response)) {
2004 $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse: ".$server_response);
2005 $_retVal = false;
2006 }
2007
2008 return $_retVal;
2009 }
2010
2011 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2020 public function socket_send_str($_strSend, $_returnCode = null, $CRLF = "\r\n")
2021 {
2022 // phpcs:enable
2023 if ($this->_debug) {
2024 $this->log .= $_strSend; // @CHANGE LDR for log
2025 }
2026 fwrite($this->socket, $_strSend.$CRLF);
2027 if ($this->_debug) {
2028 $this->log .= ' ('.$_returnCode.')'.$CRLF;
2029 }
2030
2031 if ($_returnCode) {
2032 return $this->server_parse($this->socket, $_returnCode);
2033 }
2034
2035 return null;
2036 }
2037
2038 // =============================================================
2039 // ** Error handling methods
2040
2048 private function _setErr($_errNum, $_errMsg)
2049 {
2050 $this->_smtpsErrors[] = array(
2051 'num' => $_errNum,
2052 'msg' => $_errMsg,
2053 );
2054 }
2055
2061 public function getErrors()
2062 {
2063 $_errMsg = array();
2064
2065 if (is_array($this->_smtpsErrors)) {
2066 foreach ($this->_smtpsErrors as $_err => $_info) {
2067 $_errMsg[] = 'Error ['.$_info['num'].']: '.$_info['msg'];
2068 }
2069 }
2070
2071 return implode("\n", $_errMsg);
2072 }
2073}
2074
2075
2076// =============================================================
2077// ** CSV Version Control Info
2078
Class to construct and send SMTP compliant email, even to a secure SMTP server, regardless of platfor...
$_smtpsToken
Token in case we use OAUTH2.
_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.
$_arySensitivity
Message Sensitivity.
$_smtpsCharSet
Character set Defaulted to 'iso-8859-1'.
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:
$_smtpsHost
Host Name or IP of SMTP Server to use.
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.
$_smtpsTransEncodeTypes
Content-Transfer-Encoding.
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.
$_msgReplyTo
Where are replies and errors to be sent to This can be defined via a INI file or via a setter method.
$_smtpsID
Secure SMTP Server access ID This can be defined via a INI file or via a setter method.
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 bares 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
$_log_level
Defines log level 0 - no logging 1 - connectivity logging 2 - message generation logging 3 - detail l...
getPW()
Retrieves the User Password for authentication on Mail Server.
getSubject()
Retrieves the Message Subject.
getXheader()
Retrieves the Message X-Header Content.
$_msgReferences
List of Msg-Id.
$_msgFrom
Who sent the Message This can be defined via a INI file or via a setter method.
setErrorsTo($_strErrorsTo)
Set errors to.
$_smtpsTransEncodeType
Content-Transfer-Encoding Defaulted to 0 - 7bit.
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...
$_smtpsTransEncode
Content-Transfer-Encoding Defaulted to '7bit'.
$_smtpTimeout
Sets the SMTP server timeout in seconds.
$_smtpsRelatedBoundary
Related Boundary.
setHost($_strHost)
Defines the Host Name or IP of the Mail Server to use.
$_msgPriority
Message Sensitivity Defaults to 3 - Normal.
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...
$_msgSensitivity
Message Sensitivity Defaults to ZERO - None.
setPW($_strPW)
User Password for authentication on Mail Server.
$_smtpsErrors
Class error codes and messages.
$_msgSubject
Message Subject.
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.
$_smtpMD5
Determines whether to calculate message MD5 checksum.
$_smtpsAlternativeBoundary
Alternative Boundary.
$_aryPriority
Message Priority.
$_smtpsBoundary
Boundary String for MIME separation.
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...
$_msgXheader
Custom X-Headers.
$_options
An array of options for stream_context_create()
$_smtpsPW
Secure SMTP Server access Password This can be defined via a INI file or via a setter method.
$_msgInReplyTo
List of In-Reply-To.
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...
$_mailPath
If '$_transportType' is set to '1', then this variable is used to define the UNIX file system path to...
setDebug($_vDebug=false)
Set debug.
$_msgRecipients
Who will the Message be sent to; TO, CC, BCC Multi-diminsional array containing addresses the message...
setDeliveryReceipt($_val=0)
Set delivery receipt.
_setErr($_errNum, $_errMsg)
Defines errors codes and messages for Class.
getHeader()
Constructs and returns message header.
$_debug
Place Class in" debug" mode.
setXheader($strXdata)
Message X-Header Content This is a simple "insert".
$_transportType
Determines the method inwhich the message are to be sent.
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 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.