dolibarr  19.0.0-dev
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  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
46 class SMTPs
47 {
51  private $_smtpsHost = 'localhost';
52 
57  private $_smtpsPort = '25';
58 
63  private $_smtpsID = null;
64 
69  private $_smtpsPW = null;
70 
74  private $_smtpsToken = null;
75 
80  private $_msgFrom = null;
81 
86  private $_msgReplyTo = null;
87 
93  private $_msgRecipients = null;
94 
98  private $_msgSubject = null;
99 
105  private $_msgContent = array();
106 
110  private $_msgXheader = null;
111 
116  private $_smtpsCharSet = 'iso-8859-1';
117 
122  private $_msgSensitivity = 0;
123 
127  private $_arySensitivity = array(false,
128  'Personal',
129  'Private',
130  'Company Confidential');
131 
136  private $_msgPriority = 3;
137 
141  private $_aryPriority = array('Bulk',
142  'Highest',
143  'High',
144  'Normal',
145  'Low',
146  'Lowest');
147 
153 
157  private $_smtpsTransEncodeTypes = array('7bit', // Simple 7-bit ASCII
158  '8bit', // 8-bit coding with line termination characters
159  'base64', // 3 octets encoded into 4 sextets with offset
160  'binary', // Arbitrary binary stream
161  'mac-binhex40', // Macintosh binary to hex encoding
162  'quoted-printable', // Mostly 7-bit, with 8-bit characters encoded as "=HH"
163  'uuencode'); // UUENCODE encoding
164 
169  private $_smtpsTransEncode = '7bit';
170 
174  private $_smtpsBoundary = null;
175 
179  private $_smtpsRelatedBoundary = null;
180 
185 
193  private $_transportType = 0;
194 
199  private $_mailPath = '/usr/lib/sendmail';
200 
204  private $_smtpTimeout = 10;
205 
209  private $_smtpMD5 = false;
210 
214  private $_smtpsErrors = null;
215 
223  private $_log_level = 0;
224 
228  private $_debug = false;
229 
230 
231  // @CHANGE LDR
232  public $log = '';
233  public $lastretval = '';
234 
238  public $socket;
239 
243  public $errno;
244 
248  public $errstr;
249 
250  private $_errorsTo = '';
251  private $_deliveryReceipt = 0;
252  private $_trackId = '';
253  private $_moreinheader = '';
254 
258  private $_options = array();
259 
266  public function setOptions($_options = array())
267  {
268  $this->_options = $_options;
269  }
270 
277  public function setDeliveryReceipt($_val = 0)
278  {
279  $this->_deliveryReceipt = $_val;
280  }
281 
287  public function getDeliveryReceipt()
288  {
289  return $this->_deliveryReceipt;
290  }
291 
298  public function setTrackId($_val = '')
299  {
300  $this->_trackId = $_val;
301  }
302 
309  public function setMoreInHeader($_val = '')
310  {
311  $this->_moreinheader = $_val;
312  }
313 
319  public function getTrackId()
320  {
321  return $this->_trackId;
322  }
323 
329  public function getMoreInHeader()
330  {
331  return $this->_moreinheader;
332  }
333 
340  public function setErrorsTo($_strErrorsTo)
341  {
342  if ($_strErrorsTo) {
343  $this->_errorsTo = $this->_strip_email($_strErrorsTo);
344  }
345  }
346 
353  public function getErrorsTo($_part = true)
354  {
355  $_retValue = '';
356 
357  if ($_part === true) {
358  $_retValue = $this->_errorsTo;
359  } else {
360  $_retValue = $this->_errorsTo[$_part];
361  }
362 
363  return $_retValue;
364  }
365 
372  public function setDebug($_vDebug = false)
373  {
374  $this->_debug = $_vDebug;
375  }
376 
382  public function buildRCPTlist()
383  {
384  // Pull TO list
385  $_aryToList = $this->getTO();
386  }
387 
388  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
394  private function _server_connect()
395  {
396  // phpcs:enable
397  // Default return value
398  $_retVal = true;
399 
400  // We have to make sure the HOST given is valid
401  // This is done here because '@fsockopen' will not give me this
402  // information if it failes to connect because it can't find the HOST
403  $host = $this->getHost();
404  $usetls = preg_match('@tls://@i', $host);
405 
406  $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
407  $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
408  $host = preg_replace('@tls://@i', '', $host); // Remove prefix
409 
410  // @CHANGE LDR
411  include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
412 
413  if ((!is_ip($host)) && ((gethostbyname($host)) == $host)) {
414  $this->_setErr(99, $host.' is either offline or is an invalid host name.');
415  $_retVal = false;
416  } else {
417  if (function_exists('stream_socket_client') && !empty($this->_options)) {
418  $socket_context = stream_context_create($this->_options); // An array of options for stream_context_create()
419  $this->socket = @stream_socket_client(
420  preg_replace('@tls://@i', '', $this->getHost()).// Host to 'hit', IP or domain
421  ':'.$this->getPort(), // which Port number to use
422  $this->errno, // actual system level error
423  $this->errstr, // and any text that goes with the error
424  $this->_smtpTimeout, // timeout for reading/writing data over the socket
425  STREAM_CLIENT_CONNECT,
426  $socket_context // Options for connection
427  );
428  } else {
429  $this->socket = @fsockopen(
430  preg_replace('@tls://@i', '', $this->getHost()), // Host to 'hit', IP or domain
431  $this->getPort(), // which Port number to use
432  $this->errno, // actual system level error
433  $this->errstr, // and any text that goes with the error
434  $this->_smtpTimeout // timeout for reading/writing data over the socket
435  );
436  }
437 
438  //See if we can connect to the SMTP server
439  if (is_resource($this->socket)) {
440  // Fix from PHP SMTP class by 'Chris Ryan'
441  // Sometimes the SMTP server takes a little longer to respond
442  // so we will give it a longer timeout for the first read
443  // Windows still does not have support for this timeout function
444  if (function_exists('stream_set_timeout')) {
445  stream_set_timeout($this->socket, $this->_smtpTimeout, 0);
446  }
447 
448  // Check response from Server
449  if ($_retVal = $this->server_parse($this->socket, "220")) {
450  $_retVal = $this->socket;
451  }
452  } else {
453  // This connection attempt failed.
454  // @CHANGE LDR
455  if (empty($this->errstr)) {
456  $this->errstr = 'Failed to connect with fsockopen host='.$this->getHost().' port='.$this->getPort();
457  }
458  $this->_setErr($this->errno, $this->errstr);
459  $_retVal = false;
460  }
461  }
462 
463  return $_retVal;
464  }
465 
466  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
472  private function _server_authenticate()
473  {
474  // phpcs:enable
475  global $conf;
476 
477  require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
478  // Send the RFC2554 specified EHLO.
479  // This improvment as provided by 'SirSir' to
480  // accomodate both SMTP AND ESMTP capable servers
481  $host = $this->getHost();
482  $usetls = preg_match('@tls://@i', $host);
483 
484  $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
485  $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
486  $host = preg_replace('@tls://@i', '', $host); // Remove prefix
487 
488  if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
489  $host = 'tls://'.$host;
490  }
491 
492  $hosth = $host; // so for example 'localhost' or 'smtp-relay.gmail.com'
493 
494  if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
495  if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
496  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
497  $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
498  } elseif ($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO == 1) {
499  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
500  // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
501  $hosth = $this->getFrom('addr');
502  $hosth = preg_replace('/^.*</', '', $hosth);
503  $hosth = preg_replace('/>.*$/', '', $hosth);
504  $hosth = preg_replace('/.*@/', '', $hosth);
505  } elseif ($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO == 2) {
506  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
507  global $dolibarr_main_url_root;
508  $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
509  }
510  }
511 
512  if ($_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
513  if ($usetls) {
514  /*
515  The following dialog illustrates how a client and server can start a TLS STARTTLS session:
516  S: <waits for connection on TCP port 25>
517  C: <opens connection>
518  S: 220 mail.imc.org SMTP service ready
519  C: EHLO mail.ietf.org
520  S: 250-mail.imc.org offers a warm hug of welcome
521  S: 250 STARTTLS
522  C: STARTTLS
523  S: 220 Go ahead
524  C: <starts TLS negotiation>
525  C & S: <negotiate a TLS session>
526  C & S: <check result of negotiation>
527  // Second pass EHLO
528  C: EHLO client-domain.com
529  S: 250-server-domain.com
530  S: 250 AUTH LOGIN
531  C: <continues by sending an SMTP command
532 
533  Another example here:
534  S: 220 smtp.server.com Simple Mail Transfer Service Ready
535  C: EHLO client.example.com
536  S: 250-smtp.server.com Hello client.example.com
537  S: 250-SIZE 1000000
538  S: 250-AUTH LOGIN PLAIN CRAM-MD5
539  S: 250-STARTTLS
540  S: 250 HELP
541  C: STARTTLS
542  S: 220 TLS go ahead
543  C: EHLO client.example.com *
544  S: 250-smtp.server.com Hello client.example.com
545  S: 250-SIZE 1000000
546  S: 250-AUTH LOGIN PLAIN CRAM-MD5
547  S: 250 HELP
548  C: AUTH LOGIN
549  S: 334 VXNlcm5hbWU6
550  C: adlxdkej
551  S: 334 UGFzc3dvcmQ6
552  C: lkujsefxlj
553  S: 235 2.7.0 Authentication successful
554  C: MAIL FROM:<mail@samlogic.com>
555  S: 250 OK
556  C: RCPT TO:<john@mail.com>
557  S: 250 OK
558  C: DATA
559  S: 354 Send message, end with a "." on a line by itself
560  C: <The message data (body text, subject, e-mail header, attachments etc) is sent>
561  S .
562  S: 250 OK, message accepted for delivery: queued as 12345
563  C: QUIT
564  S: 221 Bye
565  */
566  if (!$_retVal = $this->socket_send_str('STARTTLS', 220)) {
567  $this->_setErr(131, 'STARTTLS connection is not supported.');
568  return $_retVal;
569  }
570 
571  // Before 5.6.7:
572  // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_SSLv2_CLIENT|STREAM_CRYPTO_METHOD_SSLv3_CLIENT
573  // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
574  // PHP >= 5.6.7:
575  // STREAM_CRYPTO_METHOD_SSLv23_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
576  // STREAM_CRYPTO_METHOD_TLS_CLIENT = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
577 
578  $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
579  if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
580  $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
581  $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
582  }
583 
584  if (!stream_socket_enable_crypto($this->socket, true, $crypto_method)) {
585  $this->_setErr(132, 'STARTTLS connection failed.');
586  return $_retVal;
587  }
588  // Most servers expect a 2nd pass of EHLO after TLS is established to get another time
589  // the answer with list of supported AUTH methods. They may differs between non STARTTLS and with STARTTLS.
590  if (! $_retVal = $this->socket_send_str('EHLO '.$hosth, '250')) {
591  $this->_setErr(126, '"'.$hosth.'" does not support authenticated connections or temporary error. Error after 2nd sending EHLO '.$hosth.' : '.$this->lastretval);
592  return $_retVal;
593  }
594  }
595 
596  // Default authentication method is LOGIN
597  if (empty($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE)) {
598  $conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE = 'LOGIN';
599  }
600 
601  // Send Authentication to Server
602  // Check for errors along the way
603  switch ($conf->global->MAIN_MAIL_SMTPS_AUTH_TYPE) {
604  case 'NONE':
605  // 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.
606  $_retVal = true;
607  break;
608  case 'PLAIN':
609  $this->socket_send_str('AUTH PLAIN', '334');
610  // The error here just means the ID/password combo doesn't work.
611  $_retVal = $this->socket_send_str(base64_encode("\0".$this->_smtpsID."\0".$this->_smtpsPW), '235');
612  break;
613  case 'XOAUTH2':
614  // "user=$email\1auth=Bearer $token\1\1"
615  $user = $this->_smtpsID;
616  $token = $this->_smtpsToken;
617  $initRes = "user=".$user."\001auth=Bearer ".$token."\001\001";
618  $_retVal = $this->socket_send_str('AUTH XOAUTH2 '.base64_encode($initRes), '235');
619  if (!$_retVal) {
620  $this->_setErr(130, 'Error when asking for AUTH XOAUTH2');
621  }
622  break;
623  case 'LOGIN': // most common case
624  default:
625  $_retVal = $this->socket_send_str('AUTH LOGIN', '334');
626  if (!$_retVal) {
627  $this->_setErr(130, 'Error when asking for AUTH LOGIN');
628  } else {
629  // User name will not return any error, server will take anything we give it.
630  $this->socket_send_str(base64_encode($this->_smtpsID), '334');
631  // The error here just means the ID/password combo doesn't work.
632  // There is no method to determine which is the problem, ID or password
633  $_retVal = $this->socket_send_str(base64_encode($this->_smtpsPW), '235');
634  }
635  break;
636  }
637  if (!$_retVal) {
638  $this->_setErr(130, 'Invalid Authentication Credentials.');
639  }
640  } else {
641  $this->_setErr(126, '"'.$host.'" does not support authenticated connections or temporary error. Error after sending EHLO '.$hosth.' : '.$this->lastretval);
642  }
643 
644  return $_retVal;
645  }
646 
652  public function sendMsg()
653  {
654  global $conf;
655 
659  $_retVal = false;
660 
661  // Connect to Server
662  if ($this->socket = $this->_server_connect()) {
663  // If a User ID *and* a password is given, assume Authentication is desired
664  if (!empty($this->_smtpsID) && (!empty($this->_smtpsPW) || !empty($this->_smtpsToken))) {
665  // Send the RFC2554 specified EHLO.
666  $_retVal = $this->_server_authenticate();
667  } else {
668  // This is a "normal" SMTP Server "handshack"
669  // Send the RFC821 specified HELO.
670  $host = $this->getHost();
671  $usetls = preg_match('@tls://@i', $host);
672 
673  $host = preg_replace('@tcp://@i', '', $host); // Remove prefix
674  $host = preg_replace('@ssl://@i', '', $host); // Remove prefix
675  $host = preg_replace('@tls://@i', '', $host); // Remove prefix
676 
677  if ($usetls && !empty($conf->global->MAIN_SMTPS_ADD_TLS_TO_HOST_FOR_HELO)) {
678  $host = 'tls://'.$host;
679  }
680 
681  $hosth = $host;
682 
683  if (!empty($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
684  if (!is_numeric($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO)) {
685  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is a string, we use it as domain name
686  $hosth = $conf->global->MAIL_SMTP_USE_FROM_FOR_HELO;
687  } elseif ($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO == 1) {
688  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 1, we use the domain in the from.
689  // So if the from to is 'aaa <bbb@ccc.com>', we will keep 'ccc.com'
690  $hosth = $this->getFrom('addr');
691  $hosth = preg_replace('/^.*</', '', $hosth);
692  $hosth = preg_replace('/>.*$/', '', $hosth);
693  $hosth = preg_replace('/.*@/', '', $hosth);
694  } elseif ($conf->global->MAIL_SMTP_USE_FROM_FOR_HELO == 2) {
695  // If value of MAIL_SMTP_USE_FROM_FOR_HELO is 2, we use the domain in the $dolibarr_main_url_root.
696  global $dolibarr_main_url_root;
697  $hosth = getDomainFromURL($dolibarr_main_url_root, 1);
698  }
699  }
700 
701  // Send the HELO message to the SMTP server
702  $_retVal = $this->socket_send_str('HELO '.$hosth, '250');
703  }
704 
705  // Well, did we get the server answer with correct code ?
706  if ($_retVal) {
707  // From this point onward most server response codes should be 250
708  // Specify who the mail is from....
709  // This has to be the raw email address, strip the "name" off
710  $resultmailfrom = $this->socket_send_str('MAIL FROM: '.$this->getFrom('addr'), '250');
711  if (!$resultmailfrom) {
712  fclose($this->socket);
713  return false;
714  }
715 
716  // 'RCPT TO:' must be given a single address, so this has to loop
717  // through the list of addresses, regardless of TO, CC or BCC
718  // and send it out "single file"
719  foreach ($this->get_RCPT_list() as $_address) {
720  /* Note:
721  * BCC email addresses must be listed in the RCPT TO command list,
722  * but the BCC header should not be printed under the DATA command.
723  * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
724  */
725 
726  /*
727  * TODO
728  * After each 'RCPT TO:' is sent, we need to make sure it was kosher,
729  * if not, the whole message will fail
730  * If any email address fails, we will need to RESET the connection,
731  * mark the last address as "bad" and start the address loop over again.
732  * If any address fails, the entire message fails.
733  */
734  $this->socket_send_str('RCPT TO: <'.$_address.'>', '250');
735  }
736 
737  // Tell the server we are ready to start sending data
738  // with any custom headers...
739  // This is the last response code we look for until the end of the message.
740  $this->socket_send_str('DATA', '354');
741 
742  // Now we are ready for the message...
743  // Ok, all the ingredients are mixed in let's cook this puppy...
744  $this->socket_send_str($this->getHeader().$this->getBodyContent()."\r\n".'.', '250');
745 
746  // Now tell the server we are done and close the socket...
747  fputs($this->socket, 'QUIT');
748  } else {
749  // We got error code into $this->lastretval
750  }
751 
752  fclose($this->socket);
753  }
754 
755  return $_retVal;
756  }
757 
758  // =============================================================
759  // ** Setter & Getter methods
760 
761  // ** Basic System configuration
762 
788  public function setConfig($_strConfigPath = null)
789  {
794  $_retVal = true;
795 
796  // if we have a path...
797  if (!empty($_strConfigPath)) {
798  // If the path is not valid, this will NOT generate an error,
799  // it will simply return false.
800  if (!@include $_strConfigPath) {
801  $this->_setErr(110, '"'.$_strConfigPath.'" is not a valid path.');
802  $_retVal = false;
803  }
804  } else {
805  // Read the Systems php.ini file
806  // Set these properties ONLY if they are set in the php.ini file.
807  // Otherwise the default values will be used.
808  if ($_host = ini_get('SMTPs')) {
809  $this->setHost($_host);
810  }
811 
812  if ($_port = ini_get('smtp_port')) {
813  $this->setPort($_port);
814  }
815 
816  if ($_from = ini_get('sendmail_from')) {
817  $this->setFrom($_from);
818  }
819  }
820 
821  // Send back what we have
822  return $_retVal;
823  }
824 
834  public function setTransportType($_type = 0)
835  {
836  if ((is_numeric($_type)) && (($_type >= 0) && ($_type <= 3))) {
837  $this->_transportType = $_type;
838  }
839  }
840 
849  public function getTransportType()
850  {
851  return $this->_transportType;
852  }
853 
861  public function setMailPath($_path)
862  {
863  // This feature is not yet implemented
864  return true;
865 
866  //if ( $_path ) $this->_mailPath = $_path;
867  }
868 
877  public function setHost($_strHost)
878  {
879  if ($_strHost) {
880  $this->_smtpsHost = $_strHost;
881  }
882  }
883 
890  public function getHost()
891  {
892  return $this->_smtpsHost;
893  }
894 
903  public function setPort($_intPort)
904  {
905  if ((is_numeric($_intPort)) &&
906  (($_intPort >= 1) && ($_intPort <= 65536))) {
907  $this->_smtpsPort = $_intPort;
908  }
909  }
910 
917  public function getPort()
918  {
919  return $this->_smtpsPort;
920  }
921 
928  public function setID($_strID)
929  {
930  $this->_smtpsID = $_strID;
931  }
932 
938  public function getID()
939  {
940  return $this->_smtpsID;
941  }
942 
949  public function setPW($_strPW)
950  {
951  $this->_smtpsPW = $_strPW;
952  }
953 
959  public function getPW()
960  {
961  return $this->_smtpsPW;
962  }
963 
970  public function setToken($_strToken)
971  {
972  $this->_smtpsToken = $_strToken;
973  }
974 
980  public function getToken()
981  {
982  return $this->_smtpsToken;
983  }
984 
992  public function setCharSet($_strCharSet)
993  {
994  if ($_strCharSet) {
995  $this->_smtpsCharSet = $_strCharSet;
996  }
997  }
998 
1004  public function getCharSet()
1005  {
1006  return $this->_smtpsCharSet;
1007  }
1008 
1024  public function setTransEncode($_strTransEncode)
1025  {
1026  if (array_search($_strTransEncode, $this->_smtpsTransEncodeTypes)) {
1027  $this->_smtpsTransEncode = $_strTransEncode;
1028  }
1029  }
1030 
1036  public function getTransEncode()
1037  {
1038  return $this->_smtpsTransEncode;
1039  }
1040 
1057  public function setTransEncodeType($_strTransEncodeType)
1058  {
1059  if (array_search($_strTransEncodeType, $this->_smtpsTransEncodeTypes)) {
1060  $this->_smtpsTransEncodeType = $_strTransEncodeType;
1061  }
1062  }
1063 
1069  public function getTransEncodeType()
1070  {
1071  return $this->_smtpsTransEncodeTypes[$this->_smtpsTransEncodeType];
1072  }
1073 
1074 
1075  // ** Message Construction
1076 
1083  public function setFrom($_strFrom)
1084  {
1085  if ($_strFrom) {
1086  $this->_msgFrom = $this->_strip_email($_strFrom);
1087  }
1088  }
1089 
1096  public function getFrom($_part = true)
1097  {
1098  $_retValue = '';
1099 
1100  if ($_part === true) {
1101  $_retValue = $this->_msgFrom;
1102  } else {
1103  $_retValue = $this->_msgFrom[$_part];
1104  }
1105 
1106  return $_retValue;
1107  }
1108 
1115  public function setReplyTo($_strReplyTo)
1116  {
1117  if ($_strReplyTo) {
1118  $this->_msgReplyTo = $this->_strip_email($_strReplyTo);
1119  }
1120  }
1121 
1128  public function getReplyTo($_part = true)
1129  {
1130  $_retValue = '';
1131 
1132  if ($_part === true) {
1133  $_retValue = $this->_msgReplyTo;
1134  } else {
1135  $_retValue = $this->_msgReplyTo[$_part];
1136  }
1137 
1138  return $_retValue;
1139  }
1140 
1151  private function _buildAddrList($_type, $_addrList)
1152  {
1153  // Pull existing list
1154  $aryHost = $this->_msgRecipients;
1155 
1156  // Only run this if we have something
1157  if (!empty($_addrList)) {
1158  // $_addrList can be a STRING or an array
1159  if (is_string($_addrList)) {
1160  // This could be a COMMA delimited string
1161  if (strstr($_addrList, ',')) {
1162  // "explode "list" into an array
1163  $_addrList = explode(',', $_addrList);
1164  } else {
1165  // Stick it in an array
1166  $_addrList = array($_addrList);
1167  }
1168  }
1169 
1170  // take the array of addresses and split them further
1171  foreach ($_addrList as $_strAddr) {
1172  // Strip off the end '>'
1173  $_strAddr = str_replace('>', '', $_strAddr);
1174 
1175  // Seperate "Real Name" from eMail address
1176  $_tmpaddr = null;
1177  $_tmpaddr = explode('<', $_strAddr);
1178 
1179  // We have a "Real Name" and eMail address
1180  if (count($_tmpaddr) == 2) {
1181  $_tmpHost = explode('@', $_tmpaddr[1]);
1182  $_tmpaddr[0] = trim($_tmpaddr[0], ' ">');
1183  $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = $_tmpaddr[0];
1184  } else {
1185  // We only have an eMail address
1186  // Strip off the beggining '<'
1187  $_strAddr = str_replace('<', '', $_strAddr);
1188 
1189  $_tmpHost = explode('@', $_strAddr);
1190  $_tmpHost[0] = trim($_tmpHost[0]);
1191  $_tmpHost[1] = trim($_tmpHost[1]);
1192 
1193  $aryHost[$_tmpHost[1]][$_type][$_tmpHost[0]] = '';
1194  }
1195  }
1196  }
1197  // replace list
1198  $this->_msgRecipients = $aryHost;
1199  }
1200 
1201  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1218  private function _strip_email($_strAddr)
1219  {
1220  // phpcs:enable
1221  // Keep the orginal
1222  $_aryEmail['org'] = $_strAddr;
1223 
1224  // Set entire string to Lower Case
1225  $_strAddr = strtolower($_strAddr);
1226 
1227  // Drop "stuff' off the end
1228  $_strAddr = trim($_strAddr, ' ">');
1229 
1230  // Seperate "Real Name" from eMail address, if we have one
1231  $_tmpAry = explode('<', $_strAddr);
1232 
1233  // Do we have a "Real name"
1234  if (count($_tmpAry) == 2) {
1235  // We may not really have a "Real Name"
1236  if ($_tmpAry[0]) {
1237  $_aryEmail['real'] = trim($_tmpAry[0], ' ">');
1238  }
1239 
1240  $_aryEmail['addr'] = $_tmpAry[1];
1241  } else {
1242  $_aryEmail['addr'] = $_tmpAry[0];
1243  }
1244 
1245  // Pull User Name and Host.tld apart
1246  $_tmpHost = explode('@', $_aryEmail['addr']);
1247  $_aryEmail['user'] = $_tmpHost[0];
1248  $_aryEmail['host'] = $_tmpHost[1];
1249 
1250  // Put the brackets back around the address
1251  $_aryEmail['addr'] = '<'.$_aryEmail['addr'].'>';
1252 
1253  return $_aryEmail;
1254  }
1255 
1256  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1264  public function get_RCPT_list()
1265  {
1266  // phpcs:enable
1270  $_RCPT_list = array();
1271 
1272  // walk down Recipients array and pull just email addresses
1273  foreach ($this->_msgRecipients as $_host => $_list) {
1274  foreach ($_list as $_subList) {
1275  foreach ($_subList as $_name => $_addr) {
1276  // build RCPT list
1277  $_RCPT_list[] = $_name.'@'.$_host;
1278  }
1279  }
1280  }
1281 
1282  return $_RCPT_list;
1283  }
1284 
1285  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1292  public function get_email_list($_which = null)
1293  {
1294  // phpcs:enable
1295  // We need to know which address segment to pull
1296  if ($_which) {
1297  // Make sure we have addresses to process
1298  if ($this->_msgRecipients) {
1299  $_RCPT_list = array();
1300  // walk down Recipients array and pull just email addresses
1301  foreach ($this->_msgRecipients as $_host => $_list) {
1302  if (!empty($this->_msgRecipients[$_host][$_which])) {
1303  foreach ($this->_msgRecipients[$_host][$_which] as $_addr => $_realName) {
1304  if ($_realName) { // @CHANGE LDR
1305  $_realName = '"'.$_realName.'"';
1306  $_RCPT_list[] = $_realName.' <'.$_addr.'@'.$_host.'>';
1307  } else {
1308  $_RCPT_list[] = $_addr.'@'.$_host;
1309  }
1310  }
1311  }
1312  }
1313 
1314  return implode(', ', $_RCPT_list);
1315  } else {
1316  $this->_setErr(101, 'No eMail Address for message to be sent to.');
1317  return false;
1318  }
1319  } else {
1320  $this->_setErr(102, 'eMail type not defined.');
1321  return false;
1322  }
1323  }
1324 
1331  public function setTO($_addrTo)
1332  {
1333  if ($_addrTo) {
1334  $this->_buildAddrList('to', $_addrTo);
1335  }
1336  }
1337 
1343  public function getTo()
1344  {
1345  return $this->get_email_list('to');
1346  }
1347 
1354  public function setCC($_strCC)
1355  {
1356  if ($_strCC) {
1357  $this->_buildAddrList('cc', $_strCC);
1358  }
1359  }
1360 
1366  public function getCC()
1367  {
1368  return $this->get_email_list('cc');
1369  }
1370 
1377  public function setBCC($_strBCC)
1378  {
1379  if ($_strBCC) {
1380  $this->_buildAddrList('bcc', $_strBCC);
1381  }
1382  }
1383 
1389  public function getBCC()
1390  {
1391  return $this->get_email_list('bcc');
1392  }
1393 
1400  public function setSubject($_strSubject = '')
1401  {
1402  if ($_strSubject) {
1403  $this->_msgSubject = $_strSubject;
1404  }
1405  }
1406 
1412  public function getSubject()
1413  {
1414  return $this->_msgSubject;
1415  }
1416 
1422  public function getHeader()
1423  {
1424  global $conf;
1425 
1426  $_header = 'From: '.$this->getFrom('org')."\r\n"
1427  . 'To: '.$this->getTO()."\r\n";
1428 
1429  if ($this->getCC()) {
1430  $_header .= 'Cc: '.$this->getCC()."\r\n";
1431  }
1432 
1433  /* Note:
1434  * BCC email addresses must be listed in the RCPT TO command list,
1435  * but the BCC header should not be printed under the DATA command.
1436  * So it is included into the function sendMsg() but not here.
1437  * http://stackoverflow.com/questions/2750211/sending-bcc-emails-using-a-smtp-server
1438  */
1439  /*
1440  if ( $this->getBCC() )
1441  $_header .= 'Bcc: ' . $this->getBCC() . "\r\n";
1442  */
1443 
1444  $host = dol_getprefix('email');
1445 
1446  //NOTE: Message-ID should probably contain the username of the user who sent the msg
1447  $_header .= 'Subject: '.$this->getSubject()."\r\n";
1448  $_header .= 'Date: '.date("r")."\r\n";
1449 
1450  $trackid = $this->getTrackId();
1451  if ($trackid) {
1452  // References is kept in response and Message-ID is returned into In-Reply-To:
1453  $_header .= 'Message-ID: <'.time().'.SMTPs-dolibarr-'.$trackid.'@'.$host.">\r\n";
1454  $_header .= 'References: <'.time().'.SMTPs-dolibarr-'.$trackid.'@'.$host.">\r\n";
1455  $_header .= 'X-Dolibarr-TRACKID: '.$trackid.'@'.$host."\r\n";
1456  } else {
1457  $_header .= 'Message-ID: <'.time().'.SMTPs@'.$host.">\r\n";
1458  }
1459  if (!empty($_SERVER['REMOTE_ADDR'])) {
1460  $_header .= "X-RemoteAddr: ".$_SERVER['REMOTE_ADDR']."\r\n";
1461  }
1462  if ($this->getMoreInHeader()) {
1463  $_header .= $this->getMoreInHeader(); // Value must include the "\r\n";
1464  }
1465 
1466  //$_header .=
1467  // 'Read-Receipt-To: ' . $this->getFrom( 'org' ) . "\r\n"
1468  // 'Return-Receipt-To: ' . $this->getFrom( 'org' ) . "\r\n";
1469 
1470  if ($this->getSensitivity()) {
1471  $_header .= 'Sensitivity: '.$this->getSensitivity()."\r\n";
1472  }
1473 
1474  if ($this->_msgPriority != 3) {
1475  $_header .= $this->getPriority();
1476  }
1477 
1478 
1479  // @CHANGE LDR
1480  if ($this->getDeliveryReceipt()) {
1481  $_header .= 'Disposition-Notification-To: '.$this->getFrom('addr')."\r\n";
1482  }
1483  if ($this->getErrorsTo()) {
1484  $_header .= 'Errors-To: '.$this->getErrorsTo('addr')."\r\n";
1485  }
1486  if ($this->getReplyTo()) {
1487  $_header .= "Reply-To: ".$this->getReplyTo('addr')."\r\n";
1488  }
1489 
1490  $_header .= 'X-Mailer: Dolibarr version '.DOL_VERSION.' (using SMTPs Mailer)'."\r\n";
1491  $_header .= 'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART ? 'MAIN_MAIL_USE_MULTI_PART' : 'No MAIN_MAIL_USE_MULTI_PART')."\r\n";
1492  $_header .= 'Mime-Version: 1.0'."\r\n";
1493 
1494 
1495  return $_header;
1496  }
1497 
1505  public function setBodyContent($strContent, $strType = 'plain')
1506  {
1507  //if ( $strContent )
1508  //{
1509  if ($strType == 'html') {
1510  $strMimeType = 'text/html';
1511  } else {
1512  $strMimeType = 'text/plain';
1513  }
1514 
1515  // Make RFC821 Compliant, replace bare linefeeds
1516  $strContent = preg_replace("/(?<!\r)\n/si", "\r\n", $strContent);
1517 
1518  $strContentAltText = '';
1519  if ($strType == 'html') {
1520  // Similar code to forge a text from html is also in CMailFile.class.php
1521  $strContentAltText = preg_replace('/<head><title>.*<\/style><\/head>/', '', $strContent);
1522  $strContentAltText = preg_replace("/<br\s*[^>]*>/", " ", $strContentAltText);
1523  $strContentAltText = html_entity_decode(strip_tags($strContentAltText));
1524  $strContentAltText = trim(wordwrap($strContentAltText, 75, "\r\n"));
1525  }
1526 
1527  // Make RFC2045 Compliant
1528  //$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
1529  $strContent = rtrim(wordwrap($strContent, 75, "\r\n")); // TODO Using this method creates unexpected line break on text/plain content.
1530 
1531  $this->_msgContent[$strType] = array();
1532 
1533  $this->_msgContent[$strType]['mimeType'] = $strMimeType;
1534  $this->_msgContent[$strType]['data'] = $strContent;
1535  $this->_msgContent[$strType]['dataText'] = $strContentAltText;
1536 
1537  if ($this->getMD5flag()) {
1538  $this->_msgContent[$strType]['md5'] = dol_hash($strContent, 3);
1539  }
1540  //}
1541  }
1542 
1548  public function getBodyContent()
1549  {
1550  global $conf;
1551 
1552  // Generate a new Boundary string
1553  $this->_setBoundary();
1554 
1555  // What type[s] of content do we have
1556  $_types = array_keys($this->_msgContent);
1557 
1558  // How many content types do we have
1559  $keyCount = count($_types);
1560 
1561  // If we have ZERO, we have a problem
1562  if ($keyCount === 0) {
1563  die("Sorry, no content");
1564  } elseif ($keyCount === 1 && empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1565  // If we have ONE, we can use the simple format
1566  $_msgData = $this->_msgContent;
1567  $_msgData = $_msgData[$_types[0]];
1568 
1569  $content = 'Content-Type: '.$_msgData['mimeType'].'; charset="'.$this->getCharSet().'"'."\r\n"
1570  . 'Content-Transfer-Encoding: '.$this->getTransEncodeType()."\r\n"
1571  . 'Content-Disposition: inline'."\r\n"
1572  . 'Content-Description: Message'."\r\n";
1573 
1574  if ($this->getMD5flag()) {
1575  $content .= 'Content-MD5: '.$_msgData['md5']."\r\n";
1576  }
1577 
1578  $content .= "\r\n"
1579  . $_msgData['data']."\r\n";
1580  } elseif ($keyCount >= 1 || !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1581  // If we have more than ONE, we use the multi-part format
1582  // Since this is an actual multi-part message
1583  // We need to define a content message Boundary
1584  // NOTE: This was 'multipart/alternative', but Windows based mail servers have issues with this.
1585 
1586  //$content = 'Content-Type: multipart/related; boundary="' . $this->_getBoundary() . '"' . "\r\n";
1587  $content = 'Content-Type: multipart/mixed; boundary="'.$this->_getBoundary('mixed').'"'."\r\n";
1588 
1589  // . "\r\n"
1590  // . 'This is a multi-part message in MIME format.' . "\r\n";
1591  $content .= "Content-Transfer-Encoding: 8bit\r\n";
1592  $content .= "\r\n";
1593 
1594  $content .= "--".$this->_getBoundary('mixed')."\r\n";
1595 
1596  if (key_exists('image', $this->_msgContent)) { // If inline image found
1597  $content .= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"'."\r\n";
1598  $content .= "\r\n";
1599  $content .= "--".$this->_getBoundary('alternative')."\r\n";
1600  }
1601 
1602 
1603  // $this->_msgContent must be sorted with key 'text' or 'html' first then 'image' then 'attachment'
1604 
1605 
1606  // Loop through message content array
1607  foreach ($this->_msgContent as $type => $_content) {
1608  if ($type == 'attachment') {
1609  // loop through all attachments
1610  foreach ($_content as $_file => $_data) {
1611  $content .= "--".$this->_getBoundary('mixed')."\r\n"
1612  . 'Content-Disposition: attachment; filename="'.$_data['fileName'].'"'."\r\n"
1613  . 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['fileName'].'"'."\r\n"
1614  . 'Content-Transfer-Encoding: base64'."\r\n"
1615  . 'Content-Description: '.$_data['fileName']."\r\n";
1616  if (!empty($_data['cid'])) {
1617  $content .= "X-Attachment-Id: ".$_data['cid']."\r\n";
1618  $content .= "Content-ID: <".$_data['cid'].">\r\n";
1619  }
1620  if ($this->getMD5flag()) {
1621  $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1622  }
1623 
1624  $content .= "\r\n".$_data['data']."\r\n\r\n";
1625  }
1626  } elseif ($type == 'image') {
1627  // @CHANGE LDR
1628  // loop through all images
1629  foreach ($_content as $_image => $_data) {
1630  $content .= "--".$this->_getBoundary('related')."\r\n"; // always related for an inline image
1631 
1632  $content .= 'Content-Type: '.$_data['mimeType'].'; name="'.$_data['imageName'].'"'."\r\n"
1633  . 'Content-Transfer-Encoding: base64'."\r\n"
1634  . 'Content-Disposition: inline; filename="'.$_data['imageName'].'"'."\r\n"
1635  . 'Content-ID: <'.$_data['cid'].'> '."\r\n";
1636 
1637  if ($this->getMD5flag()) {
1638  $content .= 'Content-MD5: '.$_data['md5']."\r\n";
1639  }
1640 
1641  $content .= "\r\n"
1642  . $_data['data']."\r\n";
1643  }
1644 
1645  // always end related and end alternative after inline images
1646  $content .= "--".$this->_getBoundary('related')."--\r\n";
1647  $content .= "\r\n--".$this->_getBoundary('alternative')."--\r\n";
1648  $content .= "\r\n";
1649  } else {
1650  if (key_exists('image', $this->_msgContent)) {
1651  $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1652  $content .= "\r\n".($_content['dataText'] ? $_content['dataText'] : strip_tags($_content['data']))."\r\n"; // Add plain text message
1653  $content .= "--".$this->_getBoundary('alternative')."\r\n";
1654  $content .= 'Content-Type: multipart/related; boundary="'.$this->_getBoundary('related').'"'."\r\n";
1655  $content .= "\r\n";
1656  $content .= "--".$this->_getBoundary('related')."\r\n";
1657  }
1658 
1659  if (!key_exists('image', $this->_msgContent) && $_content['dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1660  // Add plain text message part before html part
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  $content .= "Content-Type: text/plain; charset=".$this->getCharSet()."\r\n";
1666  $content .= "\r\n".$_content['dataText']."\r\n";
1667  $content .= "--".$this->_getBoundary('alternative')."\r\n";
1668  }
1669 
1670  $content .= 'Content-Type: '.$_content['mimeType'].'; charset='.$this->getCharSet();
1671 
1672  $content .= "\r\n";
1673 
1674  if ($this->getMD5flag()) {
1675  $content .= 'Content-MD5: '.$_content['md5']."\r\n";
1676  }
1677 
1678  $content .= "\r\n".$_content['data']."\r\n";
1679 
1680  if (!key_exists('image', $this->_msgContent) && $_content['dataText'] && !empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) {
1681  // Add plain text message part after html part
1682  $content .= "--".$this->_getBoundary('alternative')."--\r\n";
1683  }
1684 
1685  $content .= "\r\n";
1686  }
1687  }
1688 
1689  $content .= "--".$this->_getBoundary('mixed').'--'."\r\n";
1690  }
1691 
1692  return $content;
1693  }
1694 
1705  public function setAttachment($strContent, $strFileName = 'unknown', $strMimeType = 'unknown', $strCid = '')
1706  {
1707  if ($strContent) {
1708  $strContent = rtrim(chunk_split(base64_encode($strContent), 76, "\r\n")); // 76 max is defined into http://tools.ietf.org/html/rfc2047
1709 
1710  $this->_msgContent['attachment'][$strFileName]['mimeType'] = $strMimeType;
1711  $this->_msgContent['attachment'][$strFileName]['fileName'] = $strFileName;
1712  $this->_msgContent['attachment'][$strFileName]['data'] = $strContent;
1713  $this->_msgContent['attachment'][$strFileName]['cid'] = $strCid; // If defined, it means this attachment must be shown inline
1714 
1715  if ($this->getMD5flag()) {
1716  $this->_msgContent['attachment'][$strFileName]['md5'] = dol_hash($strContent, 3);
1717  }
1718  }
1719  }
1720 
1721 
1722  // @CHANGE LDR
1723 
1734  public function setImageInline($strContent, $strImageName = 'unknown', $strMimeType = 'unknown', $strImageCid = 'unknown')
1735  {
1736  if ($strContent) {
1737  $this->_msgContent['image'][$strImageName]['mimeType'] = $strMimeType;
1738  $this->_msgContent['image'][$strImageName]['imageName'] = $strImageName;
1739  $this->_msgContent['image'][$strImageName]['cid'] = $strImageCid;
1740  $this->_msgContent['image'][$strImageName]['data'] = $strContent;
1741 
1742  if ($this->getMD5flag()) {
1743  $this->_msgContent['image'][$strImageName]['md5'] = dol_hash($strContent, 3);
1744  }
1745  }
1746  }
1747  // END @CHANGE LDR
1748 
1749 
1761  public function setSensitivity($_value = 0)
1762  {
1763  if ((is_numeric($_value)) &&
1764  (($_value >= 0) && ($_value <= 3))) {
1765  $this->_msgSensitivity = $_value;
1766  }
1767  }
1768 
1779  public function getSensitivity()
1780  {
1781  return $this->_arySensitivity[$this->_msgSensitivity];
1782  }
1783 
1797  public function setPriority($_value = 3)
1798  {
1799  if ((is_numeric($_value)) &&
1800  (($_value >= 0) && ($_value <= 5))) {
1801  $this->_msgPriority = $_value;
1802  }
1803  }
1804 
1817  public function getPriority()
1818  {
1819  return 'Importance: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1820  . 'Priority: '.$this->_aryPriority[$this->_msgPriority]."\r\n"
1821  . 'X-Priority: '.$this->_msgPriority.' ('.$this->_aryPriority[$this->_msgPriority].')'."\r\n";
1822  }
1823 
1830  public function setMD5flag($_flag = false)
1831  {
1832  $this->_smtpMD5 = $_flag;
1833  }
1834 
1840  public function getMD5flag()
1841  {
1842  return $this->_smtpMD5;
1843  }
1844 
1853  public function setXheader($strXdata)
1854  {
1855  if ($strXdata) {
1856  $this->_msgXheader[] = $strXdata;
1857  }
1858  }
1859 
1865  public function getXheader()
1866  {
1867  return $this->_msgXheader;
1868  }
1869 
1875  private function _setBoundary()
1876  {
1877  $this->_smtpsBoundary = "multipart_x.".time().".x_boundary";
1878  $this->_smtpsRelatedBoundary = 'mul_'.dol_hash(uniqid("dolibarr2"), 3);
1879  $this->_smtpsAlternativeBoundary = 'mul_'.dol_hash(uniqid("dolibarr3"), 3);
1880  }
1881 
1888  private function _getBoundary($type = 'mixed')
1889  {
1890  if ($type == 'mixed') {
1891  return $this->_smtpsBoundary;
1892  } elseif ($type == 'related') {
1894  } elseif ($type == 'alternative') {
1896  }
1897  return '';
1898  }
1899 
1900  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1911  public function server_parse($socket, $response)
1912  {
1913  // phpcs:enable
1918  $_retVal = true;
1919 
1920  $server_response = '';
1921 
1922  // avoid infinite loop
1923  $limit = 0;
1924 
1925  while (substr($server_response, 3, 1) != ' ' && $limit < 100) {
1926  if (!($server_response = fgets($socket, 256))) {
1927  $this->_setErr(121, "Couldn't get mail server response codes");
1928  $_retVal = false;
1929  break;
1930  }
1931  $this->log .= $server_response;
1932  $limit++;
1933  }
1934 
1935  $this->lastretval = substr($server_response, 0, 3);
1936 
1937  if (!(substr($server_response, 0, 3) == $response)) {
1938  $this->_setErr(120, "Ran into problems sending Mail.\r\nResponse: ".$server_response);
1939  $_retVal = false;
1940  }
1941 
1942  return $_retVal;
1943  }
1944 
1945  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1954  public function socket_send_str($_strSend, $_returnCode = null, $CRLF = "\r\n")
1955  {
1956  // phpcs:enable
1957  if ($this->_debug) {
1958  $this->log .= $_strSend; // @CHANGE LDR for log
1959  }
1960  fputs($this->socket, $_strSend.$CRLF);
1961  if ($this->_debug) {
1962  $this->log .= ' ('.$_returnCode.')'.$CRLF;
1963  }
1964 
1965  if ($_returnCode) {
1966  return $this->server_parse($this->socket, $_returnCode);
1967  }
1968 
1969  return null;
1970  }
1971 
1972  // =============================================================
1973  // ** Error handling methods
1974 
1982  private function _setErr($_errNum, $_errMsg)
1983  {
1984  $this->_smtpsErrors[] = array(
1985  'num' => $_errNum,
1986  'msg' => $_errMsg,
1987  );
1988  }
1989 
1995  public function getErrors()
1996  {
1997  $_errMsg = array();
1998 
1999  if (is_array($this->_smtpsErrors)) {
2000  foreach ($this->_smtpsErrors as $_err => $_info) {
2001  $_errMsg[] = 'Error ['.$_info['num'].']: '.$_info['msg'];
2002  }
2003  }
2004 
2005  return implode("\n", $_errMsg);
2006  }
2007 }
2008 
2009 
2010 // =============================================================
2011 // ** CSV Version Control Info
2012 
Class to construct and send SMTP compliant email, even to a secure SMTP server, regardless of platfor...
Definition: smtps.class.php:47
$_smtpsToken
Token in case we use OAUTH2.
Definition: smtps.class.php:74
_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.
Definition: smtps.class.php:51
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.
buildRCPTlist()
build RECIPIENT List, all addresses who will recieve this message
getBodyContent()
Retrieves the Message Content.
_buildAddrList($_type, $_addrList)
Inserts given addresses into structured format.
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 This is defaulted to '25' This is used only with 's...
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.
Definition: smtps.class.php:86
$_smtpsID
Secure SMTP Server access ID This can be defined via a INI file or via a setter method.
Definition: smtps.class.php:63
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 characers sets Known...
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.
$_msgFrom
Who sent the Message This can be defined via a INI file or via a setter method.
Definition: smtps.class.php:80
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.
$_smtpsPort
SMTP Server Port definition.
Definition: smtps.class.php:57
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.
Definition: smtps.class.php:98
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 seperation.
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.
Definition: smtps.class.php:69
getTransportType()
Return the method inwhich the message is to be sent.
setMailPath($_path)
Path to the sendmail execuable.
getTransEncode()
Retrieves the Content-Transfer-Encoding.
setTransEncode($_strTransEncode)
Content-Transfer-Encoding, Defaulted to '7bit' This can be changed for 2byte characers sets Known Enc...
$_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 containg addresses the message w...
Definition: smtps.class.php:93
setDeliveryReceipt($_val=0)
Set delivery receipt.
_setErr($_errNum, $_errMsg)
Defines errors codes and messages for Class.
getHeader()
Constructes 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....
getDomainFromURL($url, $mode=0)
Function get second level domain name.
Definition: geturl.lib.php:345
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.