Cheetah
class.phpmailer.php
Go to the documentation of this file.
1 <?php
28 class PHPMailer
29 {
34  public $Version = '5.2.25';
35 
42  public $Priority = null;
43 
48  public $CharSet = 'iso-8859-1';
49 
54  public $ContentType = 'text/plain';
55 
61  public $Encoding = '8bit';
62 
67  public $ErrorInfo = '';
68 
73  public $From = 'root@localhost';
74 
79  public $FromName = 'Root User';
80 
86  public $Sender = '';
87 
96  public $ReturnPath = '';
97 
102  public $Subject = '';
103 
109  public $Body = '';
110 
118  public $AltBody = '';
119 
128  public $Ical = '';
129 
135  protected $MIMEBody = '';
136 
142  protected $MIMEHeader = '';
143 
149  protected $mailHeader = '';
150 
156  public $WordWrap = 0;
157 
163  public $Mailer = 'mail';
164 
169  public $Sendmail = '/usr/sbin/sendmail';
170 
176  public $UseSendmailOptions = true;
177 
184  public $PluginDir = '';
185 
190  public $ConfirmReadingTo = '';
191 
199  public $Hostname = '';
200 
209  public $MessageID = '';
210 
216  public $MessageDate = '';
217 
229  public $Host = 'localhost';
230 
236  public $Port = 25;
237 
245  public $Helo = '';
246 
252  public $SMTPSecure = '';
253 
260  public $SMTPAutoTLS = true;
261 
269  public $SMTPAuth = false;
270 
275  public $SMTPOptions = array();
276 
281  public $Username = '';
282 
287  public $Password = '';
288 
294  public $AuthType = '';
295 
301  public $Realm = '';
302 
308  public $Workstation = '';
309 
315  public $Timeout = 300;
316 
329  public $SMTPDebug = 0;
330 
345  public $Debugoutput = 'echo';
346 
353  public $SMTPKeepAlive = false;
354 
361  public $SingleTo = false;
362 
368  public $SingleToArray = array();
369 
377  public $do_verp = false;
378 
383  public $AllowEmpty = false;
384 
391  public $LE = "\n";
392 
397  public $DKIM_selector = '';
398 
404  public $DKIM_identity = '';
405 
411  public $DKIM_passphrase = '';
412 
418  public $DKIM_domain = '';
419 
424  public $DKIM_private = '';
425 
431  public $DKIM_private_string = '';
432 
451  public $action_function = '';
452 
458  public $XMailer = '';
459 
467  public static $validator = 'auto';
468 
474  protected $smtp = null;
475 
481  protected $to = array();
482 
488  protected $cc = array();
489 
495  protected $bcc = array();
496 
502  protected $ReplyTo = array();
503 
511  protected $all_recipients = array();
512 
523  protected $RecipientsQueue = array();
524 
533  protected $ReplyToQueue = array();
534 
540  protected $attachment = array();
541 
547  protected $CustomHeader = array();
548 
554  protected $lastMessageID = '';
555 
561  protected $message_type = '';
562 
568  protected $boundary = array();
569 
575  protected $language = array();
576 
582  protected $error_count = 0;
583 
589  protected $sign_cert_file = '';
590 
596  protected $sign_key_file = '';
597 
603  protected $sign_extracerts_file = '';
604 
611  protected $sign_key_pass = '';
612 
618  protected $exceptions = false;
619 
625  protected $uniqueid = '';
626 
630  const STOP_MESSAGE = 0;
631 
635  const STOP_CONTINUE = 1;
636 
640  const STOP_CRITICAL = 2;
641 
645  const CRLF = "\r\n";
646 
651  const MAX_LINE_LENGTH = 998;
652 
657  public function __construct($exceptions = null)
658  {
659  if ($exceptions !== null) {
660  $this->exceptions = (boolean)$exceptions;
661  }
662  }
663 
667  public function __destruct()
668  {
669  //Close any open SMTP connection nicely
670  $this->smtpClose();
671  }
672 
686  private function mailPassthru($to, $subject, $body, $header, $params)
687  {
688  //Check overloading of mail function to avoid double-encoding
689  if (ini_get('mbstring.func_overload') & 1) {
690  $subject = $this->secureHeader($subject);
691  } else {
692  $subject = $this->encodeHeader($this->secureHeader($subject));
693  }
694 
695  //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
696  //@link http://php.net/manual/en/function.mail.php
697  if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
698  $result = @mail($to, $subject, $body, $header);
699  } else {
700  $result = @mail($to, $subject, $body, $header, $params);
701  }
702  return $result;
703  }
711  protected function edebug($str)
712  {
713  if ($this->SMTPDebug <= 0) {
714  return;
715  }
716  //Avoid clash with built-in function names
717  if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
718  call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
719  return;
720  }
721  switch ($this->Debugoutput) {
722  case 'error_log':
723  //Don't output, just log
724  error_log($str);
725  break;
726  case 'html':
727  //Cleans up output a bit for a better looking, HTML-safe output
728  echo htmlentities(
729  preg_replace('/[\r\n]+/', '', $str),
730  ENT_QUOTES,
731  'UTF-8'
732  )
733  . "<br>\n";
734  break;
735  case 'echo':
736  default:
737  //Normalize line breaks
738  $str = preg_replace('/\r\n?/ms', "\n", $str);
739  echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
740  "\n",
741  "\n \t ",
742  trim($str)
743  ) . "\n";
744  }
745  }
746 
752  public function isHTML($isHtml = true)
753  {
754  if ($isHtml) {
755  $this->ContentType = 'text/html';
756  } else {
757  $this->ContentType = 'text/plain';
758  }
759  }
760 
765  public function isSMTP()
766  {
767  $this->Mailer = 'smtp';
768  }
769 
774  public function isMail()
775  {
776  $this->Mailer = 'mail';
777  }
778 
783  public function isSendmail()
784  {
785  $ini_sendmail_path = ini_get('sendmail_path');
786 
787  if (!stristr($ini_sendmail_path, 'sendmail')) {
788  $this->Sendmail = '/usr/sbin/sendmail';
789  } else {
790  $this->Sendmail = $ini_sendmail_path;
791  }
792  $this->Mailer = 'sendmail';
793  }
794 
799  public function isQmail()
800  {
801  $ini_sendmail_path = ini_get('sendmail_path');
802 
803  if (!stristr($ini_sendmail_path, 'qmail')) {
804  $this->Sendmail = '/var/qmail/bin/qmail-inject';
805  } else {
806  $this->Sendmail = $ini_sendmail_path;
807  }
808  $this->Mailer = 'qmail';
809  }
810 
817  public function addAddress($address, $name = '')
818  {
819  return $this->addOrEnqueueAnAddress('to', $address, $name);
820  }
821 
829  public function addCC($address, $name = '')
830  {
831  return $this->addOrEnqueueAnAddress('cc', $address, $name);
832  }
833 
841  public function addBCC($address, $name = '')
842  {
843  return $this->addOrEnqueueAnAddress('bcc', $address, $name);
844  }
845 
852  public function addReplyTo($address, $name = '')
853  {
854  return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
855  }
856 
869  protected function addOrEnqueueAnAddress($kind, $address, $name)
870  {
871  $address = trim($address);
872  $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
873  if (($pos = strrpos($address, '@')) === false) {
874  // At-sign is misssing.
875  $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
876  $this->setError($error_message);
877  $this->edebug($error_message);
878  if ($this->exceptions) {
879  throw new phpmailerException($error_message);
880  }
881  return false;
882  }
883  $params = array($kind, $address, $name);
884  // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
885  if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
886  if ($kind != 'Reply-To') {
887  if (!array_key_exists($address, $this->RecipientsQueue)) {
888  $this->RecipientsQueue[$address] = $params;
889  return true;
890  }
891  } else {
892  if (!array_key_exists($address, $this->ReplyToQueue)) {
893  $this->ReplyToQueue[$address] = $params;
894  return true;
895  }
896  }
897  return false;
898  }
899  // Immediately add standard addresses without IDN.
900  return call_user_func_array(array($this, 'addAnAddress'), $params);
901  }
902 
913  protected function addAnAddress($kind, $address, $name = '')
914  {
915  if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
916  $error_message = $this->lang('Invalid recipient kind: ') . $kind;
917  $this->setError($error_message);
918  $this->edebug($error_message);
919  if ($this->exceptions) {
920  throw new phpmailerException($error_message);
921  }
922  return false;
923  }
924  if (!$this->validateAddress($address)) {
925  $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
926  $this->setError($error_message);
927  $this->edebug($error_message);
928  if ($this->exceptions) {
929  throw new phpmailerException($error_message);
930  }
931  return false;
932  }
933  if ($kind != 'Reply-To') {
934  if (!array_key_exists(strtolower($address), $this->all_recipients)) {
935  array_push($this->$kind, array($address, $name));
936  $this->all_recipients[strtolower($address)] = true;
937  return true;
938  }
939  } else {
940  if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
941  $this->ReplyTo[strtolower($address)] = array($address, $name);
942  return true;
943  }
944  }
945  return false;
946  }
947 
958  public function parseAddresses($addrstr, $useimap = true)
959  {
960  $addresses = array();
961  if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
962  //Use this built-in parser if it's available
963  $list = imap_rfc822_parse_adrlist($addrstr, '');
964  foreach ($list as $address) {
965  if ($address->host != '.SYNTAX-ERROR.') {
966  if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
967  $addresses[] = array(
968  'name' => (property_exists($address, 'personal') ? $address->personal : ''),
969  'address' => $address->mailbox . '@' . $address->host
970  );
971  }
972  }
973  }
974  } else {
975  //Use this simpler parser
976  $list = explode(',', $addrstr);
977  foreach ($list as $address) {
978  $address = trim($address);
979  //Is there a separate name part?
980  if (strpos($address, '<') === false) {
981  //No separate name, just use the whole thing
982  if ($this->validateAddress($address)) {
983  $addresses[] = array(
984  'name' => '',
985  'address' => $address
986  );
987  }
988  } else {
989  list($name, $email) = explode('<', $address);
990  $email = trim(str_replace('>', '', $email));
991  if ($this->validateAddress($email)) {
992  $addresses[] = array(
993  'name' => trim(str_replace(array('"', "'"), '', $name)),
994  'address' => $email
995  );
996  }
997  }
998  }
999  }
1000  return $addresses;
1001  }
1002 
1011  public function setFrom($address, $name = '', $auto = true)
1012  {
1013  $address = trim($address);
1014  $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
1015  // Don't validate now addresses with IDN. Will be done in send().
1016  if (($pos = strrpos($address, '@')) === false or
1017  (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1018  !$this->validateAddress($address)) {
1019  $error_message = $this->lang('invalid_address') . " (setFrom) $address";
1020  $this->setError($error_message);
1021  $this->edebug($error_message);
1022  if ($this->exceptions) {
1023  throw new phpmailerException($error_message);
1024  }
1025  return false;
1026  }
1027  $this->From = $address;
1028  $this->FromName = $name;
1029  if ($auto) {
1030  if (empty($this->Sender)) {
1031  $this->Sender = $address;
1032  }
1033  }
1034  return true;
1035  }
1036 
1044  public function getLastMessageID()
1045  {
1046  return $this->lastMessageID;
1047  }
1048 
1068  public static function validateAddress($address, $patternselect = null)
1069  {
1070  if (is_null($patternselect)) {
1071  $patternselect = self::$validator;
1072  }
1073  if (is_callable($patternselect)) {
1074  return call_user_func($patternselect, $address);
1075  }
1076  //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1077  if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1078  return false;
1079  }
1080  if (!$patternselect or $patternselect == 'auto') {
1081  //Check this constant first so it works when extension_loaded() is disabled by safe mode
1082  //Constant was added in PHP 5.2.4
1083  if (defined('PCRE_VERSION')) {
1084  //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1085  if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1086  $patternselect = 'pcre8';
1087  } else {
1088  $patternselect = 'pcre';
1089  }
1090  } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1091  //Fall back to older PCRE
1092  $patternselect = 'pcre';
1093  } else {
1094  //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1095  if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1096  $patternselect = 'php';
1097  } else {
1098  $patternselect = 'noregex';
1099  }
1100  }
1101  }
1102  switch ($patternselect) {
1103  case 'pcre8':
1110  return (boolean)preg_match(
1111  '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1112  '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\‍((?>(?2)' .
1113  '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\‍)))+(?2))|(?2))?)' .
1114  '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1115  '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1116  '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1117  '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1118  '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1119  '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1120  $address
1121  );
1122  case 'pcre':
1123  //An older regex that doesn't need a recent PCRE
1124  return (boolean)preg_match(
1125  '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1126  '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1127  '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1128  '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1129  '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1130  '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1131  '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1132  '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1133  '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1134  '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1135  $address
1136  );
1137  case 'html5':
1142  return (boolean)preg_match(
1143  '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1144  '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1145  $address
1146  );
1147  case 'noregex':
1148  //No PCRE! Do something _very_ approximate!
1149  //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1150  return (strlen($address) >= 3
1151  and strpos($address, '@') >= 1
1152  and strpos($address, '@') != strlen($address) - 1);
1153  case 'php':
1154  default:
1155  return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1156  }
1157  }
1158 
1164  public function idnSupported()
1165  {
1166  // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1167  return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1168  }
1169 
1181  public function punyencodeAddress($address)
1182  {
1183  // Verify we have required functions, CharSet, and at-sign.
1184  if ($this->idnSupported() and
1185  !empty($this->CharSet) and
1186  ($pos = strrpos($address, '@')) !== false) {
1187  $domain = substr($address, ++$pos);
1188  // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1189  if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1190  $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1191  if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1192  idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1193  idn_to_ascii($domain)) !== false) {
1194  return substr($address, 0, $pos) . $punycode;
1195  }
1196  }
1197  }
1198  return $address;
1199  }
1200 
1207  public function send()
1208  {
1209  try {
1210  if (!$this->preSend()) {
1211  return false;
1212  }
1213  return $this->postSend();
1214  } catch (phpmailerException $exc) {
1215  $this->mailHeader = '';
1216  $this->setError($exc->getMessage());
1217  if ($this->exceptions) {
1218  throw $exc;
1219  }
1220  return false;
1221  }
1222  }
1223 
1229  public function preSend()
1230  {
1231  try {
1232  $this->error_count = 0; // Reset errors
1233  $this->mailHeader = '';
1234 
1235  // Dequeue recipient and Reply-To addresses with IDN
1236  foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1237  $params[1] = $this->punyencodeAddress($params[1]);
1238  call_user_func_array(array($this, 'addAnAddress'), $params);
1239  }
1240  if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1241  throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1242  }
1243 
1244  // Validate From, Sender, and ConfirmReadingTo addresses
1245  foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1246  $this->$address_kind = trim($this->$address_kind);
1247  if (empty($this->$address_kind)) {
1248  continue;
1249  }
1250  $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1251  if (!$this->validateAddress($this->$address_kind)) {
1252  $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
1253  $this->setError($error_message);
1254  $this->edebug($error_message);
1255  if ($this->exceptions) {
1256  throw new phpmailerException($error_message);
1257  }
1258  return false;
1259  }
1260  }
1261 
1262  // Set whether the message is multipart/alternative
1263  if ($this->alternativeExists()) {
1264  $this->ContentType = 'multipart/alternative';
1265  }
1266 
1267  $this->setMessageType();
1268  // Refuse to send an empty message unless we are specifically allowing it
1269  if (!$this->AllowEmpty and empty($this->Body)) {
1270  throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1271  }
1272 
1273  // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1274  $this->MIMEHeader = '';
1275  $this->MIMEBody = $this->createBody();
1276  // createBody may have added some headers, so retain them
1277  $tempheaders = $this->MIMEHeader;
1278  $this->MIMEHeader = $this->createHeader();
1279  $this->MIMEHeader .= $tempheaders;
1280 
1281  // To capture the complete message when using mail(), create
1282  // an extra header list which createHeader() doesn't fold in
1283  if ($this->Mailer == 'mail') {
1284  if (count($this->to) > 0) {
1285  $this->mailHeader .= $this->addrAppend('To', $this->to);
1286  } else {
1287  $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1288  }
1289  $this->mailHeader .= $this->headerLine(
1290  'Subject',
1291  $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1292  );
1293  }
1294 
1295  // Sign with DKIM if enabled
1296  if (!empty($this->DKIM_domain)
1297  && !empty($this->DKIM_selector)
1298  && (!empty($this->DKIM_private_string)
1299  || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
1300  )
1301  ) {
1302  $header_dkim = $this->DKIM_Add(
1303  $this->MIMEHeader . $this->mailHeader,
1304  $this->encodeHeader($this->secureHeader($this->Subject)),
1305  $this->MIMEBody
1306  );
1307  $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1308  str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1309  }
1310  return true;
1311  } catch (phpmailerException $exc) {
1312  $this->setError($exc->getMessage());
1313  if ($this->exceptions) {
1314  throw $exc;
1315  }
1316  return false;
1317  }
1318  }
1319 
1326  public function postSend()
1327  {
1328  try {
1329  // Choose the mailer and send through it
1330  switch ($this->Mailer) {
1331  case 'sendmail':
1332  case 'qmail':
1333  return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1334  case 'smtp':
1335  return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1336  case 'mail':
1337  return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1338  default:
1339  $sendMethod = $this->Mailer.'Send';
1340  if (method_exists($this, $sendMethod)) {
1341  return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1342  }
1343 
1344  return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1345  }
1346  } catch (phpmailerException $exc) {
1347  $this->setError($exc->getMessage());
1348  $this->edebug($exc->getMessage());
1349  if ($this->exceptions) {
1350  throw $exc;
1351  }
1352  }
1353  return false;
1354  }
1355 
1365  protected function sendmailSend($header, $body)
1366  {
1367  // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1368  if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
1369  if ($this->Mailer == 'qmail') {
1370  $sendmailFmt = '%s -f%s';
1371  } else {
1372  $sendmailFmt = '%s -oi -f%s -t';
1373  }
1374  } else {
1375  if ($this->Mailer == 'qmail') {
1376  $sendmailFmt = '%s';
1377  } else {
1378  $sendmailFmt = '%s -oi -t';
1379  }
1380  }
1381 
1382  // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing.
1383  $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1384 
1385  if ($this->SingleTo) {
1386  foreach ($this->SingleToArray as $toAddr) {
1387  if (!@$mail = popen($sendmail, 'w')) {
1388  throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1389  }
1390  fputs($mail, 'To: ' . $toAddr . "\n");
1391  fputs($mail, $header);
1392  fputs($mail, $body);
1393  $result = pclose($mail);
1394  $this->doCallback(
1395  ($result == 0),
1396  array($toAddr),
1397  $this->cc,
1398  $this->bcc,
1399  $this->Subject,
1400  $body,
1401  $this->From
1402  );
1403  if ($result != 0) {
1404  throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1405  }
1406  }
1407  } else {
1408  if (!@$mail = popen($sendmail, 'w')) {
1409  throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1410  }
1411  fputs($mail, $header);
1412  fputs($mail, $body);
1413  $result = pclose($mail);
1414  $this->doCallback(
1415  ($result == 0),
1416  $this->to,
1417  $this->cc,
1418  $this->bcc,
1419  $this->Subject,
1420  $body,
1421  $this->From
1422  );
1423  if ($result != 0) {
1424  throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1425  }
1426  }
1427  return true;
1428  }
1429 
1439  protected static function isShellSafe($string)
1440  {
1441  // Future-proof
1442  if (escapeshellcmd($string) !== $string
1443  or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
1444  ) {
1445  return false;
1446  }
1447 
1448  $length = strlen($string);
1449 
1450  for ($i = 0; $i < $length; $i++) {
1451  $c = $string[$i];
1452 
1453  // All other characters have a special meaning in at least one common shell, including = and +.
1454  // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
1455  // Note that this does permit non-Latin alphanumeric characters based on the current locale.
1456  if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1457  return false;
1458  }
1459  }
1460 
1461  return true;
1462  }
1463 
1473  protected function mailSend($header, $body)
1474  {
1475  $toArr = array();
1476  foreach ($this->to as $toaddr) {
1477  $toArr[] = $this->addrFormat($toaddr);
1478  }
1479  $to = implode(', ', $toArr);
1480 
1481  $params = null;
1482  //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
1483  if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1484  // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1485  if (self::isShellSafe($this->Sender)) {
1486  $params = sprintf('-f%s', $this->Sender);
1487  }
1488  }
1489  if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
1490  $old_from = ini_get('sendmail_from');
1491  ini_set('sendmail_from', $this->Sender);
1492  }
1493  $result = false;
1494  if ($this->SingleTo and count($toArr) > 1) {
1495  foreach ($toArr as $toAddr) {
1496  $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1497  $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1498  }
1499  } else {
1500  $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1501  $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1502  }
1503  if (isset($old_from)) {
1504  ini_set('sendmail_from', $old_from);
1505  }
1506  if (!$result) {
1507  throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1508  }
1509  return true;
1510  }
1511 
1517  public function getSMTPInstance()
1518  {
1519  if (!is_object($this->smtp)) {
1520  $this->smtp = new SMTP;
1521  }
1522  return $this->smtp;
1523  }
1524 
1537  protected function smtpSend($header, $body)
1538  {
1539  $bad_rcpt = array();
1540  if (!$this->smtpConnect($this->SMTPOptions)) {
1541  throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1542  }
1543  if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1544  $smtp_from = $this->Sender;
1545  } else {
1546  $smtp_from = $this->From;
1547  }
1548  if (!$this->smtp->mail($smtp_from)) {
1549  $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1550  throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1551  }
1552 
1553  // Attempt to send to all recipients
1554  foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1555  foreach ($togroup as $to) {
1556  if (!$this->smtp->recipient($to[0])) {
1557  $error = $this->smtp->getError();
1558  $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1559  $isSent = false;
1560  } else {
1561  $isSent = true;
1562  }
1563  $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1564  }
1565  }
1566 
1567  // Only send the DATA command if we have viable recipients
1568  if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1569  throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1570  }
1571  if ($this->SMTPKeepAlive) {
1572  $this->smtp->reset();
1573  } else {
1574  $this->smtp->quit();
1575  $this->smtp->close();
1576  }
1577  //Create error message for any bad addresses
1578  if (count($bad_rcpt) > 0) {
1579  $errstr = '';
1580  foreach ($bad_rcpt as $bad) {
1581  $errstr .= $bad['to'] . ': ' . $bad['error'];
1582  }
1583  throw new phpmailerException(
1584  $this->lang('recipients_failed') . $errstr,
1585  self::STOP_CONTINUE
1586  );
1587  }
1588  return true;
1589  }
1590 
1600  public function smtpConnect($options = null)
1601  {
1602  if (is_null($this->smtp)) {
1603  $this->smtp = $this->getSMTPInstance();
1604  }
1605 
1606  //If no options are provided, use whatever is set in the instance
1607  if (is_null($options)) {
1608  $options = $this->SMTPOptions;
1609  }
1610 
1611  // Already connected?
1612  if ($this->smtp->connected()) {
1613  return true;
1614  }
1615 
1616  $this->smtp->setTimeout($this->Timeout);
1617  $this->smtp->setDebugLevel($this->SMTPDebug);
1618  $this->smtp->setDebugOutput($this->Debugoutput);
1619  $this->smtp->setVerp($this->do_verp);
1620  $hosts = explode(';', $this->Host);
1621  $lastexception = null;
1622 
1623  foreach ($hosts as $hostentry) {
1624  $hostinfo = array();
1625  if (!preg_match(
1626  '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
1627  trim($hostentry),
1628  $hostinfo
1629  )) {
1630  // Not a valid host entry
1631  $this->edebug('Ignoring invalid host: ' . $hostentry);
1632  continue;
1633  }
1634  // $hostinfo[2]: optional ssl or tls prefix
1635  // $hostinfo[3]: the hostname
1636  // $hostinfo[4]: optional port number
1637  // The host string prefix can temporarily override the current setting for SMTPSecure
1638  // If it's not specified, the default value is used
1639  $prefix = '';
1640  $secure = $this->SMTPSecure;
1641  $tls = ($this->SMTPSecure == 'tls');
1642  if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1643  $prefix = 'ssl://';
1644  $tls = false; // Can't have SSL and TLS at the same time
1645  $secure = 'ssl';
1646  } elseif ($hostinfo[2] == 'tls') {
1647  $tls = true;
1648  // tls doesn't use a prefix
1649  $secure = 'tls';
1650  }
1651  //Do we need the OpenSSL extension?
1652  $sslext = defined('OPENSSL_ALGO_SHA1');
1653  if ('tls' === $secure or 'ssl' === $secure) {
1654  //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1655  if (!$sslext) {
1656  throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1657  }
1658  }
1659  $host = $hostinfo[3];
1660  $port = $this->Port;
1661  $tport = (integer)$hostinfo[4];
1662  if ($tport > 0 and $tport < 65536) {
1663  $port = $tport;
1664  }
1665  if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1666  try {
1667  if ($this->Helo) {
1668  $hello = $this->Helo;
1669  } else {
1670  $hello = $this->serverHostname();
1671  }
1672  $this->smtp->hello($hello);
1673  //Automatically enable TLS encryption if:
1674  // * it's not disabled
1675  // * we have openssl extension
1676  // * we are not already using SSL
1677  // * the server offers STARTTLS
1678  if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1679  $tls = true;
1680  }
1681  if ($tls) {
1682  if (!$this->smtp->startTLS()) {
1683  throw new phpmailerException($this->lang('connect_host'));
1684  }
1685  // We must resend EHLO after TLS negotiation
1686  $this->smtp->hello($hello);
1687  }
1688  if ($this->SMTPAuth) {
1689  if (!$this->smtp->authenticate(
1690  $this->Username,
1691  $this->Password,
1692  $this->AuthType,
1693  $this->Realm,
1694  $this->Workstation
1695  )
1696  ) {
1697  throw new phpmailerException($this->lang('authenticate'));
1698  }
1699  }
1700  return true;
1701  } catch (phpmailerException $exc) {
1702  $lastexception = $exc;
1703  $this->edebug($exc->getMessage());
1704  // We must have connected, but then failed TLS or Auth, so close connection nicely
1705  $this->smtp->quit();
1706  }
1707  }
1708  }
1709  // If we get here, all connection attempts have failed, so close connection hard
1710  $this->smtp->close();
1711  // As we've caught all exceptions, just report whatever the last one was
1712  if ($this->exceptions and !is_null($lastexception)) {
1713  throw $lastexception;
1714  }
1715  return false;
1716  }
1717 
1722  public function smtpClose()
1723  {
1724  if (is_a($this->smtp, 'SMTP')) {
1725  if ($this->smtp->connected()) {
1726  $this->smtp->quit();
1727  $this->smtp->close();
1728  }
1729  }
1730  }
1731 
1741  public function setLanguage($langcode = 'en', $lang_path = '')
1742  {
1743  // Backwards compatibility for renamed language codes
1744  $renamed_langcodes = array(
1745  'br' => 'pt_br',
1746  'cz' => 'cs',
1747  'dk' => 'da',
1748  'no' => 'nb',
1749  'se' => 'sv',
1750  'sr' => 'rs'
1751  );
1752 
1753  if (isset($renamed_langcodes[$langcode])) {
1754  $langcode = $renamed_langcodes[$langcode];
1755  }
1756 
1757  // Define full set of translatable strings in English
1758  $PHPMAILER_LANG = array(
1759  'authenticate' => 'SMTP Error: Could not authenticate.',
1760  'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1761  'data_not_accepted' => 'SMTP Error: data not accepted.',
1762  'empty_message' => 'Message body empty',
1763  'encoding' => 'Unknown encoding: ',
1764  'execute' => 'Could not execute: ',
1765  'file_access' => 'Could not access file: ',
1766  'file_open' => 'File Error: Could not open file: ',
1767  'from_failed' => 'The following From address failed: ',
1768  'instantiate' => 'Could not instantiate mail function.',
1769  'invalid_address' => 'Invalid address: ',
1770  'mailer_not_supported' => ' mailer is not supported.',
1771  'provide_address' => 'You must provide at least one recipient email address.',
1772  'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1773  'signing' => 'Signing Error: ',
1774  'smtp_connect_failed' => 'SMTP connect() failed.',
1775  'smtp_error' => 'SMTP server error: ',
1776  'variable_set' => 'Cannot set or reset variable: ',
1777  'extension_missing' => 'Extension missing: '
1778  );
1779  if (empty($lang_path)) {
1780  // Calculate an absolute path so it can work if CWD is not here
1781  $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1782  }
1783  //Validate $langcode
1784  if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
1785  $langcode = 'en';
1786  }
1787  $foundlang = true;
1788  $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1789  // There is no English translation file
1790  if ($langcode != 'en') {
1791  // Make sure language file path is readable
1792  if (!is_readable($lang_file)) {
1793  $foundlang = false;
1794  } else {
1795  // Overwrite language-specific strings.
1796  // This way we'll never have missing translation keys.
1797  $foundlang = include $lang_file;
1798  }
1799  }
1800  $this->language = $PHPMAILER_LANG;
1801  return (boolean)$foundlang; // Returns false if language not found
1802  }
1803 
1808  public function getTranslations()
1809  {
1810  return $this->language;
1811  }
1812 
1823  public function addrAppend($type, $addr)
1824  {
1825  $addresses = array();
1826  foreach ($addr as $address) {
1827  $addresses[] = $this->addrFormat($address);
1828  }
1829  return $type . ': ' . implode(', ', $addresses) . $this->LE;
1830  }
1831 
1839  public function addrFormat($addr)
1840  {
1841  if (empty($addr[1])) { // No name provided
1842  return $this->secureHeader($addr[0]);
1843  } else {
1844  return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1845  $addr[0]
1846  ) . '>';
1847  }
1848  }
1849 
1861  public function wrapText($message, $length, $qp_mode = false)
1862  {
1863  if ($qp_mode) {
1864  $soft_break = sprintf(' =%s', $this->LE);
1865  } else {
1866  $soft_break = $this->LE;
1867  }
1868  // If utf-8 encoding is used, we will need to make sure we don't
1869  // split multibyte characters when we wrap
1870  $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1871  $lelen = strlen($this->LE);
1872  $crlflen = strlen(self::CRLF);
1873 
1874  $message = $this->fixEOL($message);
1875  //Remove a trailing line break
1876  if (substr($message, -$lelen) == $this->LE) {
1877  $message = substr($message, 0, -$lelen);
1878  }
1879 
1880  //Split message into lines
1881  $lines = explode($this->LE, $message);
1882  //Message will be rebuilt in here
1883  $message = '';
1884  foreach ($lines as $line) {
1885  $words = explode(' ', $line);
1886  $buf = '';
1887  $firstword = true;
1888  foreach ($words as $word) {
1889  if ($qp_mode and (strlen($word) > $length)) {
1890  $space_left = $length - strlen($buf) - $crlflen;
1891  if (!$firstword) {
1892  if ($space_left > 20) {
1893  $len = $space_left;
1894  if ($is_utf8) {
1895  $len = $this->utf8CharBoundary($word, $len);
1896  } elseif (substr($word, $len - 1, 1) == '=') {
1897  $len--;
1898  } elseif (substr($word, $len - 2, 1) == '=') {
1899  $len -= 2;
1900  }
1901  $part = substr($word, 0, $len);
1902  $word = substr($word, $len);
1903  $buf .= ' ' . $part;
1904  $message .= $buf . sprintf('=%s', self::CRLF);
1905  } else {
1906  $message .= $buf . $soft_break;
1907  }
1908  $buf = '';
1909  }
1910  while (strlen($word) > 0) {
1911  if ($length <= 0) {
1912  break;
1913  }
1914  $len = $length;
1915  if ($is_utf8) {
1916  $len = $this->utf8CharBoundary($word, $len);
1917  } elseif (substr($word, $len - 1, 1) == '=') {
1918  $len--;
1919  } elseif (substr($word, $len - 2, 1) == '=') {
1920  $len -= 2;
1921  }
1922  $part = substr($word, 0, $len);
1923  $word = substr($word, $len);
1924 
1925  if (strlen($word) > 0) {
1926  $message .= $part . sprintf('=%s', self::CRLF);
1927  } else {
1928  $buf = $part;
1929  }
1930  }
1931  } else {
1932  $buf_o = $buf;
1933  if (!$firstword) {
1934  $buf .= ' ';
1935  }
1936  $buf .= $word;
1937 
1938  if (strlen($buf) > $length and $buf_o != '') {
1939  $message .= $buf_o . $soft_break;
1940  $buf = $word;
1941  }
1942  }
1943  $firstword = false;
1944  }
1945  $message .= $buf . self::CRLF;
1946  }
1947 
1948  return $message;
1949  }
1950 
1960  public function utf8CharBoundary($encodedText, $maxLength)
1961  {
1962  $foundSplitPos = false;
1963  $lookBack = 3;
1964  while (!$foundSplitPos) {
1965  $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1966  $encodedCharPos = strpos($lastChunk, '=');
1967  if (false !== $encodedCharPos) {
1968  // Found start of encoded character byte within $lookBack block.
1969  // Check the encoded byte value (the 2 chars after the '=')
1970  $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1971  $dec = hexdec($hex);
1972  if ($dec < 128) {
1973  // Single byte character.
1974  // If the encoded char was found at pos 0, it will fit
1975  // otherwise reduce maxLength to start of the encoded char
1976  if ($encodedCharPos > 0) {
1977  $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1978  }
1979  $foundSplitPos = true;
1980  } elseif ($dec >= 192) {
1981  // First byte of a multi byte character
1982  // Reduce maxLength to split at start of character
1983  $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1984  $foundSplitPos = true;
1985  } elseif ($dec < 192) {
1986  // Middle byte of a multi byte character, look further back
1987  $lookBack += 3;
1988  }
1989  } else {
1990  // No encoded character found
1991  $foundSplitPos = true;
1992  }
1993  }
1994  return $maxLength;
1995  }
1996 
2005  public function setWordWrap()
2006  {
2007  if ($this->WordWrap < 1) {
2008  return;
2009  }
2010 
2011  switch ($this->message_type) {
2012  case 'alt':
2013  case 'alt_inline':
2014  case 'alt_attach':
2015  case 'alt_inline_attach':
2016  $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
2017  break;
2018  default:
2019  $this->Body = $this->wrapText($this->Body, $this->WordWrap);
2020  break;
2021  }
2022  }
2023 
2029  public function createHeader()
2030  {
2031  $result = '';
2032 
2033  $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
2034 
2035  // To be created automatically by mail()
2036  if ($this->SingleTo) {
2037  if ($this->Mailer != 'mail') {
2038  foreach ($this->to as $toaddr) {
2039  $this->SingleToArray[] = $this->addrFormat($toaddr);
2040  }
2041  }
2042  } else {
2043  if (count($this->to) > 0) {
2044  if ($this->Mailer != 'mail') {
2045  $result .= $this->addrAppend('To', $this->to);
2046  }
2047  } elseif (count($this->cc) == 0) {
2048  $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2049  }
2050  }
2051 
2052  $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2053 
2054  // sendmail and mail() extract Cc from the header before sending
2055  if (count($this->cc) > 0) {
2056  $result .= $this->addrAppend('Cc', $this->cc);
2057  }
2058 
2059  // sendmail and mail() extract Bcc from the header before sending
2060  if ((
2061  $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2062  )
2063  and count($this->bcc) > 0
2064  ) {
2065  $result .= $this->addrAppend('Bcc', $this->bcc);
2066  }
2067 
2068  if (count($this->ReplyTo) > 0) {
2069  $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2070  }
2071 
2072  // mail() sets the subject itself
2073  if ($this->Mailer != 'mail') {
2074  $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2075  }
2076 
2077  // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
2078  // https://tools.ietf.org/html/rfc5322#section-3.6.4
2079  if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2080  $this->lastMessageID = $this->MessageID;
2081  } else {
2082  $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2083  }
2084  $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2085  if (!is_null($this->Priority)) {
2086  $result .= $this->headerLine('X-Priority', $this->Priority);
2087  }
2088  if ($this->XMailer == '') {
2089  $result .= $this->headerLine(
2090  'X-Mailer',
2091  'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2092  );
2093  } else {
2094  $myXmailer = trim($this->XMailer);
2095  if ($myXmailer) {
2096  $result .= $this->headerLine('X-Mailer', $myXmailer);
2097  }
2098  }
2099 
2100  if ($this->ConfirmReadingTo != '') {
2101  $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2102  }
2103 
2104  // Add custom headers
2105  foreach ($this->CustomHeader as $header) {
2106  $result .= $this->headerLine(
2107  trim($header[0]),
2108  $this->encodeHeader(trim($header[1]))
2109  );
2110  }
2111  if (!$this->sign_key_file) {
2112  $result .= $this->headerLine('MIME-Version', '1.0');
2113  $result .= $this->getMailMIME();
2114  }
2115 
2116  return $result;
2117  }
2118 
2124  public function getMailMIME()
2125  {
2126  $result = '';
2127  $ismultipart = true;
2128  switch ($this->message_type) {
2129  case 'inline':
2130  $result .= $this->headerLine('Content-Type', 'multipart/related;');
2131  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2132  break;
2133  case 'attach':
2134  case 'inline_attach':
2135  case 'alt_attach':
2136  case 'alt_inline_attach':
2137  $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2138  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2139  break;
2140  case 'alt':
2141  case 'alt_inline':
2142  $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2143  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2144  break;
2145  default:
2146  // Catches case 'plain': and case '':
2147  $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2148  $ismultipart = false;
2149  break;
2150  }
2151  // RFC1341 part 5 says 7bit is assumed if not specified
2152  if ($this->Encoding != '7bit') {
2153  // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2154  if ($ismultipart) {
2155  if ($this->Encoding == '8bit') {
2156  $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2157  }
2158  // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2159  } else {
2160  $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2161  }
2162  }
2163 
2164  if ($this->Mailer != 'mail') {
2165  $result .= $this->LE;
2166  }
2167 
2168  return $result;
2169  }
2170 
2179  public function getSentMIMEMessage()
2180  {
2181  return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2182  }
2183 
2188  protected function generateId() {
2189  return md5(uniqid(time()));
2190  }
2191 
2199  public function createBody()
2200  {
2201  $body = '';
2202  //Create unique IDs and preset boundaries
2203  $this->uniqueid = $this->generateId();
2204  $this->boundary[1] = 'b1_' . $this->uniqueid;
2205  $this->boundary[2] = 'b2_' . $this->uniqueid;
2206  $this->boundary[3] = 'b3_' . $this->uniqueid;
2207 
2208  if ($this->sign_key_file) {
2209  $body .= $this->getMailMIME() . $this->LE;
2210  }
2211 
2212  $this->setWordWrap();
2213 
2214  $bodyEncoding = $this->Encoding;
2215  $bodyCharSet = $this->CharSet;
2216  //Can we do a 7-bit downgrade?
2217  if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2218  $bodyEncoding = '7bit';
2219  //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2220  $bodyCharSet = 'us-ascii';
2221  }
2222  //If lines are too long, and we're not already using an encoding that will shorten them,
2223  //change to quoted-printable transfer encoding for the body part only
2224  if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2225  $bodyEncoding = 'quoted-printable';
2226  }
2227 
2228  $altBodyEncoding = $this->Encoding;
2229  $altBodyCharSet = $this->CharSet;
2230  //Can we do a 7-bit downgrade?
2231  if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2232  $altBodyEncoding = '7bit';
2233  //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2234  $altBodyCharSet = 'us-ascii';
2235  }
2236  //If lines are too long, and we're not already using an encoding that will shorten them,
2237  //change to quoted-printable transfer encoding for the alt body part only
2238  if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2239  $altBodyEncoding = 'quoted-printable';
2240  }
2241  //Use this as a preamble in all multipart message types
2242  $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2243  switch ($this->message_type) {
2244  case 'inline':
2245  $body .= $mimepre;
2246  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2247  $body .= $this->encodeString($this->Body, $bodyEncoding);
2248  $body .= $this->LE . $this->LE;
2249  $body .= $this->attachAll('inline', $this->boundary[1]);
2250  break;
2251  case 'attach':
2252  $body .= $mimepre;
2253  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2254  $body .= $this->encodeString($this->Body, $bodyEncoding);
2255  $body .= $this->LE . $this->LE;
2256  $body .= $this->attachAll('attachment', $this->boundary[1]);
2257  break;
2258  case 'inline_attach':
2259  $body .= $mimepre;
2260  $body .= $this->textLine('--' . $this->boundary[1]);
2261  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2262  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2263  $body .= $this->LE;
2264  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2265  $body .= $this->encodeString($this->Body, $bodyEncoding);
2266  $body .= $this->LE . $this->LE;
2267  $body .= $this->attachAll('inline', $this->boundary[2]);
2268  $body .= $this->LE;
2269  $body .= $this->attachAll('attachment', $this->boundary[1]);
2270  break;
2271  case 'alt':
2272  $body .= $mimepre;
2273  $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2274  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2275  $body .= $this->LE . $this->LE;
2276  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2277  $body .= $this->encodeString($this->Body, $bodyEncoding);
2278  $body .= $this->LE . $this->LE;
2279  if (!empty($this->Ical)) {
2280  $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2281  $body .= $this->encodeString($this->Ical, $this->Encoding);
2282  $body .= $this->LE . $this->LE;
2283  }
2284  $body .= $this->endBoundary($this->boundary[1]);
2285  break;
2286  case 'alt_inline':
2287  $body .= $mimepre;
2288  $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2289  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2290  $body .= $this->LE . $this->LE;
2291  $body .= $this->textLine('--' . $this->boundary[1]);
2292  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2293  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2294  $body .= $this->LE;
2295  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2296  $body .= $this->encodeString($this->Body, $bodyEncoding);
2297  $body .= $this->LE . $this->LE;
2298  $body .= $this->attachAll('inline', $this->boundary[2]);
2299  $body .= $this->LE;
2300  $body .= $this->endBoundary($this->boundary[1]);
2301  break;
2302  case 'alt_attach':
2303  $body .= $mimepre;
2304  $body .= $this->textLine('--' . $this->boundary[1]);
2305  $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2306  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2307  $body .= $this->LE;
2308  $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2309  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2310  $body .= $this->LE . $this->LE;
2311  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2312  $body .= $this->encodeString($this->Body, $bodyEncoding);
2313  $body .= $this->LE . $this->LE;
2314  $body .= $this->endBoundary($this->boundary[2]);
2315  $body .= $this->LE;
2316  $body .= $this->attachAll('attachment', $this->boundary[1]);
2317  break;
2318  case 'alt_inline_attach':
2319  $body .= $mimepre;
2320  $body .= $this->textLine('--' . $this->boundary[1]);
2321  $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2322  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2323  $body .= $this->LE;
2324  $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2325  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2326  $body .= $this->LE . $this->LE;
2327  $body .= $this->textLine('--' . $this->boundary[2]);
2328  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2329  $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2330  $body .= $this->LE;
2331  $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2332  $body .= $this->encodeString($this->Body, $bodyEncoding);
2333  $body .= $this->LE . $this->LE;
2334  $body .= $this->attachAll('inline', $this->boundary[3]);
2335  $body .= $this->LE;
2336  $body .= $this->endBoundary($this->boundary[2]);
2337  $body .= $this->LE;
2338  $body .= $this->attachAll('attachment', $this->boundary[1]);
2339  break;
2340  default:
2341  // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
2342  //Reset the `Encoding` property in case we changed it for line length reasons
2343  $this->Encoding = $bodyEncoding;
2344  $body .= $this->encodeString($this->Body, $this->Encoding);
2345  break;
2346  }
2347 
2348  if ($this->isError()) {
2349  $body = '';
2350  } elseif ($this->sign_key_file) {
2351  try {
2352  if (!defined('PKCS7_TEXT')) {
2353  throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2354  }
2355  // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2356  $file = tempnam(sys_get_temp_dir(), 'mail');
2357  if (false === file_put_contents($file, $body)) {
2358  throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2359  }
2360  $signed = tempnam(sys_get_temp_dir(), 'signed');
2361  //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2362  if (empty($this->sign_extracerts_file)) {
2363  $sign = @openssl_pkcs7_sign(
2364  $file,
2365  $signed,
2366  'file://' . realpath($this->sign_cert_file),
2367  array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2368  null
2369  );
2370  } else {
2371  $sign = @openssl_pkcs7_sign(
2372  $file,
2373  $signed,
2374  'file://' . realpath($this->sign_cert_file),
2375  array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2376  null,
2377  PKCS7_DETACHED,
2378  $this->sign_extracerts_file
2379  );
2380  }
2381  if ($sign) {
2382  @unlink($file);
2383  $body = file_get_contents($signed);
2384  @unlink($signed);
2385  //The message returned by openssl contains both headers and body, so need to split them up
2386  $parts = explode("\n\n", $body, 2);
2387  $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2388  $body = $parts[1];
2389  } else {
2390  @unlink($file);
2391  @unlink($signed);
2392  throw new phpmailerException($this->lang('signing') . openssl_error_string());
2393  }
2394  } catch (phpmailerException $exc) {
2395  $body = '';
2396  if ($this->exceptions) {
2397  throw $exc;
2398  }
2399  }
2400  }
2401  return $body;
2402  }
2403 
2413  protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2414  {
2415  $result = '';
2416  if ($charSet == '') {
2417  $charSet = $this->CharSet;
2418  }
2419  if ($contentType == '') {
2420  $contentType = $this->ContentType;
2421  }
2422  if ($encoding == '') {
2423  $encoding = $this->Encoding;
2424  }
2425  $result .= $this->textLine('--' . $boundary);
2426  $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2427  $result .= $this->LE;
2428  // RFC1341 part 5 says 7bit is assumed if not specified
2429  if ($encoding != '7bit') {
2430  $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2431  }
2432  $result .= $this->LE;
2433 
2434  return $result;
2435  }
2436 
2443  protected function endBoundary($boundary)
2444  {
2445  return $this->LE . '--' . $boundary . '--' . $this->LE;
2446  }
2447 
2454  protected function setMessageType()
2455  {
2456  $type = array();
2457  if ($this->alternativeExists()) {
2458  $type[] = 'alt';
2459  }
2460  if ($this->inlineImageExists()) {
2461  $type[] = 'inline';
2462  }
2463  if ($this->attachmentExists()) {
2464  $type[] = 'attach';
2465  }
2466  $this->message_type = implode('_', $type);
2467  if ($this->message_type == '') {
2468  //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
2469  $this->message_type = 'plain';
2470  }
2471  }
2472 
2480  public function headerLine($name, $value)
2481  {
2482  return $name . ': ' . $value . $this->LE;
2483  }
2484 
2491  public function textLine($value)
2492  {
2493  return $value . $this->LE;
2494  }
2495 
2508  public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2509  {
2510  try {
2511  if (!@is_file($path)) {
2512  throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2513  }
2514 
2515  // If a MIME type is not specified, try to work it out from the file name
2516  if ($type == '') {
2517  $type = self::filenameToType($path);
2518  }
2519 
2520  $filename = basename($path);
2521  if ($name == '') {
2522  $name = $filename;
2523  }
2524 
2525  $this->attachment[] = array(
2526  0 => $path,
2527  1 => $filename,
2528  2 => $name,
2529  3 => $encoding,
2530  4 => $type,
2531  5 => false, // isStringAttachment
2532  6 => $disposition,
2533  7 => 0
2534  );
2535 
2536  } catch (phpmailerException $exc) {
2537  $this->setError($exc->getMessage());
2538  $this->edebug($exc->getMessage());
2539  if ($this->exceptions) {
2540  throw $exc;
2541  }
2542  return false;
2543  }
2544  return true;
2545  }
2546 
2551  public function getAttachments()
2552  {
2553  return $this->attachment;
2554  }
2555 
2564  protected function attachAll($disposition_type, $boundary)
2565  {
2566  // Return text of body
2567  $mime = array();
2568  $cidUniq = array();
2569  $incl = array();
2570 
2571  // Add all attachments
2572  foreach ($this->attachment as $attachment) {
2573  // Check if it is a valid disposition_filter
2574  if ($attachment[6] == $disposition_type) {
2575  // Check for string attachment
2576  $string = '';
2577  $path = '';
2578  $bString = $attachment[5];
2579  if ($bString) {
2580  $string = $attachment[0];
2581  } else {
2582  $path = $attachment[0];
2583  }
2584 
2585  $inclhash = md5(serialize($attachment));
2586  if (in_array($inclhash, $incl)) {
2587  continue;
2588  }
2589  $incl[] = $inclhash;
2590  $name = $attachment[2];
2591  $encoding = $attachment[3];
2592  $type = $attachment[4];
2593  $disposition = $attachment[6];
2594  $cid = $attachment[7];
2595  if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2596  continue;
2597  }
2598  $cidUniq[$cid] = true;
2599 
2600  $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2601  //Only include a filename property if we have one
2602  if (!empty($name)) {
2603  $mime[] = sprintf(
2604  'Content-Type: %s; name="%s"%s',
2605  $type,
2606  $this->encodeHeader($this->secureHeader($name)),
2607  $this->LE
2608  );
2609  } else {
2610  $mime[] = sprintf(
2611  'Content-Type: %s%s',
2612  $type,
2613  $this->LE
2614  );
2615  }
2616  // RFC1341 part 5 says 7bit is assumed if not specified
2617  if ($encoding != '7bit') {
2618  $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2619  }
2620 
2621  if ($disposition == 'inline') {
2622  $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2623  }
2624 
2625  // If a filename contains any of these chars, it should be quoted,
2626  // but not otherwise: RFC2183 & RFC2045 5.1
2627  // Fixes a warning in IETF's msglint MIME checker
2628  // Allow for bypassing the Content-Disposition header totally
2629  if (!(empty($disposition))) {
2630  $encoded_name = $this->encodeHeader($this->secureHeader($name));
2631  if (preg_match('/[ \‍(\‍)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2632  $mime[] = sprintf(
2633  'Content-Disposition: %s; filename="%s"%s',
2634  $disposition,
2635  $encoded_name,
2636  $this->LE . $this->LE
2637  );
2638  } else {
2639  if (!empty($encoded_name)) {
2640  $mime[] = sprintf(
2641  'Content-Disposition: %s; filename=%s%s',
2642  $disposition,
2643  $encoded_name,
2644  $this->LE . $this->LE
2645  );
2646  } else {
2647  $mime[] = sprintf(
2648  'Content-Disposition: %s%s',
2649  $disposition,
2650  $this->LE . $this->LE
2651  );
2652  }
2653  }
2654  } else {
2655  $mime[] = $this->LE;
2656  }
2657 
2658  // Encode as string attachment
2659  if ($bString) {
2660  $mime[] = $this->encodeString($string, $encoding);
2661  if ($this->isError()) {
2662  return '';
2663  }
2664  $mime[] = $this->LE . $this->LE;
2665  } else {
2666  $mime[] = $this->encodeFile($path, $encoding);
2667  if ($this->isError()) {
2668  return '';
2669  }
2670  $mime[] = $this->LE . $this->LE;
2671  }
2672  }
2673  }
2674 
2675  $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2676 
2677  return implode('', $mime);
2678  }
2679 
2689  protected function encodeFile($path, $encoding = 'base64')
2690  {
2691  try {
2692  if (!is_readable($path)) {
2693  throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2694  }
2695  $magic_quotes = get_magic_quotes_runtime();
2696  if ($magic_quotes) {
2697  if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2698  set_magic_quotes_runtime(false);
2699  } else {
2700  //Doesn't exist in PHP 5.4, but we don't need to check because
2701  //get_magic_quotes_runtime always returns false in 5.4+
2702  //so it will never get here
2703  ini_set('magic_quotes_runtime', false);
2704  }
2705  }
2706  $file_buffer = file_get_contents($path);
2707  $file_buffer = $this->encodeString($file_buffer, $encoding);
2708  if ($magic_quotes) {
2709  if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2710  set_magic_quotes_runtime($magic_quotes);
2711  } else {
2712  ini_set('magic_quotes_runtime', $magic_quotes);
2713  }
2714  }
2715  return $file_buffer;
2716  } catch (Exception $exc) {
2717  $this->setError($exc->getMessage());
2718  return '';
2719  }
2720  }
2721 
2730  public function encodeString($str, $encoding = 'base64')
2731  {
2732  $encoded = '';
2733  switch (strtolower($encoding)) {
2734  case 'base64':
2735  $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2736  break;
2737  case '7bit':
2738  case '8bit':
2739  $encoded = $this->fixEOL($str);
2740  // Make sure it ends with a line break
2741  if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2742  $encoded .= $this->LE;
2743  }
2744  break;
2745  case 'binary':
2746  $encoded = $str;
2747  break;
2748  case 'quoted-printable':
2749  $encoded = $this->encodeQP($str);
2750  break;
2751  default:
2752  $this->setError($this->lang('encoding') . $encoding);
2753  break;
2754  }
2755  return $encoded;
2756  }
2757 
2766  public function encodeHeader($str, $position = 'text')
2767  {
2768  $matchcount = 0;
2769  switch (strtolower($position)) {
2770  case 'phrase':
2771  if (!preg_match('/[\200-\377]/', $str)) {
2772  // Can't use addslashes as we don't know the value of magic_quotes_sybase
2773  $encoded = addcslashes($str, "\0..\37\177\\\"");
2774  if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2775  return ($encoded);
2776  } else {
2777  return ("\"$encoded\"");
2778  }
2779  }
2780  $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2781  break;
2783  case 'comment':
2784  $matchcount = preg_match_all('/[()"]/', $str, $matches);
2785  // Intentional fall-through
2786  case 'text':
2787  default:
2788  $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2789  break;
2790  }
2791 
2792  //There are no chars that need encoding
2793  if ($matchcount == 0) {
2794  return ($str);
2795  }
2796 
2797  $maxlen = 75 - 7 - strlen($this->CharSet);
2798  // Try to select the encoding which should produce the shortest output
2799  if ($matchcount > strlen($str) / 3) {
2800  // More than a third of the content will need encoding, so B encoding will be most efficient
2801  $encoding = 'B';
2802  if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2803  // Use a custom function which correctly encodes and wraps long
2804  // multibyte strings without breaking lines within a character
2805  $encoded = $this->base64EncodeWrapMB($str, "\n");
2806  } else {
2807  $encoded = base64_encode($str);
2808  $maxlen -= $maxlen % 4;
2809  $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2810  }
2811  } else {
2812  $encoding = 'Q';
2813  $encoded = $this->encodeQ($str, $position);
2814  $encoded = $this->wrapText($encoded, $maxlen, true);
2815  $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2816  }
2817 
2818  $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2819  $encoded = trim(str_replace("\n", $this->LE, $encoded));
2820 
2821  return $encoded;
2822  }
2823 
2830  public function hasMultiBytes($str)
2831  {
2832  if (function_exists('mb_strlen')) {
2833  return (strlen($str) > mb_strlen($str, $this->CharSet));
2834  } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2835  return false;
2836  }
2837  }
2838 
2844  public function has8bitChars($text)
2845  {
2846  return (boolean)preg_match('/[\x80-\xFF]/', $text);
2847  }
2848 
2859  public function base64EncodeWrapMB($str, $linebreak = null)
2860  {
2861  $start = '=?' . $this->CharSet . '?B?';
2862  $end = '?=';
2863  $encoded = '';
2864  if ($linebreak === null) {
2865  $linebreak = $this->LE;
2866  }
2867 
2868  $mb_length = mb_strlen($str, $this->CharSet);
2869  // Each line must have length <= 75, including $start and $end
2870  $length = 75 - strlen($start) - strlen($end);
2871  // Average multi-byte ratio
2872  $ratio = $mb_length / strlen($str);
2873  // Base64 has a 4:3 ratio
2874  $avgLength = floor($length * $ratio * .75);
2875 
2876  for ($i = 0; $i < $mb_length; $i += $offset) {
2877  $lookBack = 0;
2878  do {
2879  $offset = $avgLength - $lookBack;
2880  $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2881  $chunk = base64_encode($chunk);
2882  $lookBack++;
2883  } while (strlen($chunk) > $length);
2884  $encoded .= $chunk . $linebreak;
2885  }
2886 
2887  // Chomp the last linefeed
2888  $encoded = substr($encoded, 0, -strlen($linebreak));
2889  return $encoded;
2890  }
2891 
2901  public function encodeQP($string, $line_max = 76)
2902  {
2903  // Use native function if it's available (>= PHP5.3)
2904  if (function_exists('quoted_printable_encode')) {
2905  return quoted_printable_encode($string);
2906  }
2907  // Fall back to a pure PHP implementation
2908  $string = str_replace(
2909  array('%20', '%0D%0A.', '%0D%0A', '%'),
2910  array(' ', "\r\n=2E", "\r\n", '='),
2911  rawurlencode($string)
2912  );
2913  return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2914  }
2915 
2926  public function encodeQPphp(
2927  $string,
2928  $line_max = 76, $space_conv = false
2930  ) {
2931  return $this->encodeQP($string, $line_max);
2932  }
2933 
2942  public function encodeQ($str, $position = 'text')
2943  {
2944  // There should not be any EOL in the string
2945  $pattern = '';
2946  $encoded = str_replace(array("\r", "\n"), '', $str);
2947  switch (strtolower($position)) {
2948  case 'phrase':
2949  // RFC 2047 section 5.3
2950  $pattern = '^A-Za-z0-9!*+\/ -';
2951  break;
2953  case 'comment':
2954  // RFC 2047 section 5.2
2955  $pattern = '\‍(\‍)"';
2956  // intentional fall-through
2957  // for this reason we build the $pattern without including delimiters and []
2958  case 'text':
2959  default:
2960  // RFC 2047 section 5.1
2961  // Replace every high ascii, control, =, ? and _ characters
2962  $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2963  break;
2964  }
2965  $matches = array();
2966  if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2967  // If the string contains an '=', make sure it's the first thing we replace
2968  // so as to avoid double-encoding
2969  $eqkey = array_search('=', $matches[0]);
2970  if (false !== $eqkey) {
2971  unset($matches[0][$eqkey]);
2972  array_unshift($matches[0], '=');
2973  }
2974  foreach (array_unique($matches[0]) as $char) {
2975  $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2976  }
2977  }
2978  // Replace every spaces to _ (more readable than =20)
2979  return str_replace(' ', '_', $encoded);
2980  }
2981 
2993  public function addStringAttachment(
2994  $string,
2995  $filename,
2996  $encoding = 'base64',
2997  $type = '',
2998  $disposition = 'attachment'
2999  ) {
3000  // If a MIME type is not specified, try to work it out from the file name
3001  if ($type == '') {
3002  $type = self::filenameToType($filename);
3003  }
3004  // Append to $attachment array
3005  $this->attachment[] = array(
3006  0 => $string,
3007  1 => $filename,
3008  2 => basename($filename),
3009  3 => $encoding,
3010  4 => $type,
3011  5 => true, // isStringAttachment
3012  6 => $disposition,
3013  7 => 0
3014  );
3015  }
3016 
3034  public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3035  {
3036  if (!@is_file($path)) {
3037  $this->setError($this->lang('file_access') . $path);
3038  return false;
3039  }
3040 
3041  // If a MIME type is not specified, try to work it out from the file name
3042  if ($type == '') {
3043  $type = self::filenameToType($path);
3044  }
3045 
3046  $filename = basename($path);
3047  if ($name == '') {
3048  $name = $filename;
3049  }
3050 
3051  // Append to $attachment array
3052  $this->attachment[] = array(
3053  0 => $path,
3054  1 => $filename,
3055  2 => $name,
3056  3 => $encoding,
3057  4 => $type,
3058  5 => false, // isStringAttachment
3059  6 => $disposition,
3060  7 => $cid
3061  );
3062  return true;
3063  }
3064 
3079  public function addStringEmbeddedImage(
3080  $string,
3081  $cid,
3082  $name = '',
3083  $encoding = 'base64',
3084  $type = '',
3085  $disposition = 'inline'
3086  ) {
3087  // If a MIME type is not specified, try to work it out from the name
3088  if ($type == '' and !empty($name)) {
3089  $type = self::filenameToType($name);
3090  }
3091 
3092  // Append to $attachment array
3093  $this->attachment[] = array(
3094  0 => $string,
3095  1 => $name,
3096  2 => $name,
3097  3 => $encoding,
3098  4 => $type,
3099  5 => true, // isStringAttachment
3100  6 => $disposition,
3101  7 => $cid
3102  );
3103  return true;
3104  }
3105 
3111  public function inlineImageExists()
3112  {
3113  foreach ($this->attachment as $attachment) {
3114  if ($attachment[6] == 'inline') {
3115  return true;
3116  }
3117  }
3118  return false;
3119  }
3120 
3125  public function attachmentExists()
3126  {
3127  foreach ($this->attachment as $attachment) {
3128  if ($attachment[6] == 'attachment') {
3129  return true;
3130  }
3131  }
3132  return false;
3133  }
3134 
3139  public function alternativeExists()
3140  {
3141  return !empty($this->AltBody);
3142  }
3143 
3150  public function clearQueuedAddresses($kind)
3151  {
3153  foreach ($RecipientsQueue as $address => $params) {
3154  if ($params[0] == $kind) {
3155  unset($this->RecipientsQueue[$address]);
3156  }
3157  }
3158  }
3159 
3164  public function clearAddresses()
3165  {
3166  foreach ($this->to as $to) {
3167  unset($this->all_recipients[strtolower($to[0])]);
3168  }
3169  $this->to = array();
3170  $this->clearQueuedAddresses('to');
3171  }
3172 
3177  public function clearCCs()
3178  {
3179  foreach ($this->cc as $cc) {
3180  unset($this->all_recipients[strtolower($cc[0])]);
3181  }
3182  $this->cc = array();
3183  $this->clearQueuedAddresses('cc');
3184  }
3185 
3190  public function clearBCCs()
3191  {
3192  foreach ($this->bcc as $bcc) {
3193  unset($this->all_recipients[strtolower($bcc[0])]);
3194  }
3195  $this->bcc = array();
3196  $this->clearQueuedAddresses('bcc');
3197  }
3198 
3203  public function clearReplyTos()
3204  {
3205  $this->ReplyTo = array();
3206  $this->ReplyToQueue = array();
3207  }
3208 
3213  public function clearAllRecipients()
3214  {
3215  $this->to = array();
3216  $this->cc = array();
3217  $this->bcc = array();
3218  $this->all_recipients = array();
3219  $this->RecipientsQueue = array();
3220  }
3221 
3226  public function clearAttachments()
3227  {
3228  $this->attachment = array();
3229  }
3230 
3235  public function clearCustomHeaders()
3236  {
3237  $this->CustomHeader = array();
3238  }
3239 
3246  protected function setError($msg)
3247  {
3248  $this->error_count++;
3249  if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3250  $lasterror = $this->smtp->getError();
3251  if (!empty($lasterror['error'])) {
3252  $msg .= $this->lang('smtp_error') . $lasterror['error'];
3253  if (!empty($lasterror['detail'])) {
3254  $msg .= ' Detail: '. $lasterror['detail'];
3255  }
3256  if (!empty($lasterror['smtp_code'])) {
3257  $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3258  }
3259  if (!empty($lasterror['smtp_code_ex'])) {
3260  $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3261  }
3262  }
3263  }
3264  $this->ErrorInfo = $msg;
3265  }
3266 
3273  public static function rfcDate()
3274  {
3275  // Set the time zone to whatever the default is to avoid 500 errors
3276  // Will default to UTC if it's not set properly in php.ini
3277  date_default_timezone_set(@date_default_timezone_get());
3278  return date('D, j M Y H:i:s O');
3279  }
3280 
3287  protected function serverHostname()
3288  {
3289  $result = 'localhost.localdomain';
3290  if (!empty($this->Hostname)) {
3291  $result = $this->Hostname;
3292  } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3293  $result = $_SERVER['SERVER_NAME'];
3294  } elseif (function_exists('gethostname') && gethostname() !== false) {
3295  $result = gethostname();
3296  } elseif (php_uname('n') !== false) {
3297  $result = php_uname('n');
3298  }
3299  return $result;
3300  }
3301 
3308  protected function lang($key)
3309  {
3310  if (count($this->language) < 1) {
3311  $this->setLanguage('en'); // set the default language
3312  }
3313 
3314  if (array_key_exists($key, $this->language)) {
3315  if ($key == 'smtp_connect_failed') {
3316  //Include a link to troubleshooting docs on SMTP connection failure
3317  //this is by far the biggest cause of support questions
3318  //but it's usually not PHPMailer's fault.
3319  return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3320  }
3321  return $this->language[$key];
3322  } else {
3323  //Return the key as a fallback
3324  return $key;
3325  }
3326  }
3327 
3333  public function isError()
3334  {
3335  return ($this->error_count > 0);
3336  }
3337 
3345  public function fixEOL($str)
3346  {
3347  // Normalise to \n
3348  $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3349  // Now convert LE as needed
3350  if ($this->LE !== "\n") {
3351  $nstr = str_replace("\n", $this->LE, $nstr);
3352  }
3353  return $nstr;
3354  }
3355 
3365  public function addCustomHeader($name, $value = null)
3366  {
3367  if ($value === null) {
3368  // Value passed in as name:value
3369  $this->CustomHeader[] = explode(':', $name, 2);
3370  } else {
3371  $this->CustomHeader[] = array($name, $value);
3372  }
3373  }
3374 
3379  public function getCustomHeaders()
3380  {
3381  return $this->CustomHeader;
3382  }
3383 
3400  public function msgHTML($message, $basedir = '', $advanced = false)
3401  {
3402  preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3403  if (array_key_exists(2, $images)) {
3404  if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3405  // Ensure $basedir has a trailing /
3406  $basedir .= '/';
3407  }
3408  foreach ($images[2] as $imgindex => $url) {
3409  // Convert data URIs into embedded images
3410  if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3411  $data = substr($url, strpos($url, ','));
3412  if ($match[2]) {
3413  $data = base64_decode($data);
3414  } else {
3415  $data = rawurldecode($data);
3416  }
3417  $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3418  if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3419  $message = str_replace(
3420  $images[0][$imgindex],
3421  $images[1][$imgindex] . '="cid:' . $cid . '"',
3422  $message
3423  );
3424  }
3425  continue;
3426  }
3427  if (
3428  // Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
3429  !empty($basedir)
3430  // Ignore URLs containing parent dir traversal (..)
3431  && (strpos($url, '..') === false)
3432  // Do not change urls that are already inline images
3433  && substr($url, 0, 4) !== 'cid:'
3434  // Do not change absolute URLs, including anonymous protocol
3435  && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
3436  ) {
3437  $filename = basename($url);
3438  $directory = dirname($url);
3439  if ($directory == '.') {
3440  $directory = '';
3441  }
3442  $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3443  if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3444  $directory .= '/';
3445  }
3446  if ($this->addEmbeddedImage(
3447  $basedir . $directory . $filename,
3448  $cid,
3449  $filename,
3450  'base64',
3451  self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3452  )
3453  ) {
3454  $message = preg_replace(
3455  '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3456  $images[1][$imgindex] . '="cid:' . $cid . '"',
3457  $message
3458  );
3459  }
3460  }
3461  }
3462  }
3463  $this->isHTML(true);
3464  // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3465  $this->Body = $this->normalizeBreaks($message);
3466  $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3467  if (!$this->alternativeExists()) {
3468  $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3469  self::CRLF . self::CRLF;
3470  }
3471  return $this->Body;
3472  }
3473 
3494  public function html2text($html, $advanced = false)
3495  {
3496  if (is_callable($advanced)) {
3497  return call_user_func($advanced, $html);
3498  }
3499  return html_entity_decode(
3500  trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3501  ENT_QUOTES,
3502  $this->CharSet
3503  );
3504  }
3505 
3513  public static function _mime_types($ext = '')
3514  {
3515  $mimes = array(
3516  'xl' => 'application/excel',
3517  'js' => 'application/javascript',
3518  'hqx' => 'application/mac-binhex40',
3519  'cpt' => 'application/mac-compactpro',
3520  'bin' => 'application/macbinary',
3521  'doc' => 'application/msword',
3522  'word' => 'application/msword',
3523  'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3524  'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3525  'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3526  'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3527  'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3528  'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3529  'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3530  'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3531  'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
3532  'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3533  'class' => 'application/octet-stream',
3534  'dll' => 'application/octet-stream',
3535  'dms' => 'application/octet-stream',
3536  'exe' => 'application/octet-stream',
3537  'lha' => 'application/octet-stream',
3538  'lzh' => 'application/octet-stream',
3539  'psd' => 'application/octet-stream',
3540  'sea' => 'application/octet-stream',
3541  'so' => 'application/octet-stream',
3542  'oda' => 'application/oda',
3543  'pdf' => 'application/pdf',
3544  'ai' => 'application/postscript',
3545  'eps' => 'application/postscript',
3546  'ps' => 'application/postscript',
3547  'smi' => 'application/smil',
3548  'smil' => 'application/smil',
3549  'mif' => 'application/vnd.mif',
3550  'xls' => 'application/vnd.ms-excel',
3551  'ppt' => 'application/vnd.ms-powerpoint',
3552  'wbxml' => 'application/vnd.wap.wbxml',
3553  'wmlc' => 'application/vnd.wap.wmlc',
3554  'dcr' => 'application/x-director',
3555  'dir' => 'application/x-director',
3556  'dxr' => 'application/x-director',
3557  'dvi' => 'application/x-dvi',
3558  'gtar' => 'application/x-gtar',
3559  'php3' => 'application/x-httpd-php',
3560  'php4' => 'application/x-httpd-php',
3561  'php' => 'application/x-httpd-php',
3562  'phtml' => 'application/x-httpd-php',
3563  'phps' => 'application/x-httpd-php-source',
3564  'swf' => 'application/x-shockwave-flash',
3565  'sit' => 'application/x-stuffit',
3566  'tar' => 'application/x-tar',
3567  'tgz' => 'application/x-tar',
3568  'xht' => 'application/xhtml+xml',
3569  'xhtml' => 'application/xhtml+xml',
3570  'zip' => 'application/zip',
3571  'mid' => 'audio/midi',
3572  'midi' => 'audio/midi',
3573  'mp2' => 'audio/mpeg',
3574  'mp3' => 'audio/mpeg',
3575  'mpga' => 'audio/mpeg',
3576  'aif' => 'audio/x-aiff',
3577  'aifc' => 'audio/x-aiff',
3578  'aiff' => 'audio/x-aiff',
3579  'ram' => 'audio/x-pn-realaudio',
3580  'rm' => 'audio/x-pn-realaudio',
3581  'rpm' => 'audio/x-pn-realaudio-plugin',
3582  'ra' => 'audio/x-realaudio',
3583  'wav' => 'audio/x-wav',
3584  'bmp' => 'image/bmp',
3585  'gif' => 'image/gif',
3586  'jpeg' => 'image/jpeg',
3587  'jpe' => 'image/jpeg',
3588  'jpg' => 'image/jpeg',
3589  'png' => 'image/png',
3590  'tiff' => 'image/tiff',
3591  'tif' => 'image/tiff',
3592  'eml' => 'message/rfc822',
3593  'css' => 'text/css',
3594  'html' => 'text/html',
3595  'htm' => 'text/html',
3596  'shtml' => 'text/html',
3597  'log' => 'text/plain',
3598  'text' => 'text/plain',
3599  'txt' => 'text/plain',
3600  'rtx' => 'text/richtext',
3601  'rtf' => 'text/rtf',
3602  'vcf' => 'text/vcard',
3603  'vcard' => 'text/vcard',
3604  'xml' => 'text/xml',
3605  'xsl' => 'text/xml',
3606  'mpeg' => 'video/mpeg',
3607  'mpe' => 'video/mpeg',
3608  'mpg' => 'video/mpeg',
3609  'mov' => 'video/quicktime',
3610  'qt' => 'video/quicktime',
3611  'rv' => 'video/vnd.rn-realvideo',
3612  'avi' => 'video/x-msvideo',
3613  'movie' => 'video/x-sgi-movie'
3614  );
3615  if (array_key_exists(strtolower($ext), $mimes)) {
3616  return $mimes[strtolower($ext)];
3617  }
3618  return 'application/octet-stream';
3619  }
3620 
3628  public static function filenameToType($filename)
3629  {
3630  // In case the path is a URL, strip any query string before getting extension
3631  $qpos = strpos($filename, '?');
3632  if (false !== $qpos) {
3633  $filename = substr($filename, 0, $qpos);
3634  }
3635  $pathinfo = self::mb_pathinfo($filename);
3636  return self::_mime_types($pathinfo['extension']);
3637  }
3638 
3650  public static function mb_pathinfo($path, $options = null)
3651  {
3652  $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3653  $pathinfo = array();
3654  if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3655  if (array_key_exists(1, $pathinfo)) {
3656  $ret['dirname'] = $pathinfo[1];
3657  }
3658  if (array_key_exists(2, $pathinfo)) {
3659  $ret['basename'] = $pathinfo[2];
3660  }
3661  if (array_key_exists(5, $pathinfo)) {
3662  $ret['extension'] = $pathinfo[5];
3663  }
3664  if (array_key_exists(3, $pathinfo)) {
3665  $ret['filename'] = $pathinfo[3];
3666  }
3667  }
3668  switch ($options) {
3669  case PATHINFO_DIRNAME:
3670  case 'dirname':
3671  return $ret['dirname'];
3672  case PATHINFO_BASENAME:
3673  case 'basename':
3674  return $ret['basename'];
3675  case PATHINFO_EXTENSION:
3676  case 'extension':
3677  return $ret['extension'];
3678  case PATHINFO_FILENAME:
3679  case 'filename':
3680  return $ret['filename'];
3681  default:
3682  return $ret;
3683  }
3684  }
3685 
3700  public function set($name, $value = '')
3701  {
3702  if (property_exists($this, $name)) {
3703  $this->$name = $value;
3704  return true;
3705  } else {
3706  $this->setError($this->lang('variable_set') . $name);
3707  return false;
3708  }
3709  }
3710 
3717  public function secureHeader($str)
3718  {
3719  return trim(str_replace(array("\r", "\n"), '', $str));
3720  }
3721 
3732  public static function normalizeBreaks($text, $breaktype = "\r\n")
3733  {
3734  return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3735  }
3736 
3745  public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3746  {
3747  $this->sign_cert_file = $cert_filename;
3748  $this->sign_key_file = $key_filename;
3749  $this->sign_key_pass = $key_pass;
3750  $this->sign_extracerts_file = $extracerts_filename;
3751  }
3752 
3759  public function DKIM_QP($txt)
3760  {
3761  $line = '';
3762  for ($i = 0; $i < strlen($txt); $i++) {
3763  $ord = ord($txt[$i]);
3764  if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3765  $line .= $txt[$i];
3766  } else {
3767  $line .= '=' . sprintf('%02X', $ord);
3768  }
3769  }
3770  return $line;
3771  }
3772 
3780  public function DKIM_Sign($signHeader)
3781  {
3782  if (!defined('PKCS7_TEXT')) {
3783  if ($this->exceptions) {
3784  throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3785  }
3786  return '';
3787  }
3788  $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3789  if ('' != $this->DKIM_passphrase) {
3790  $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3791  } else {
3792  $privKey = openssl_pkey_get_private($privKeyStr);
3793  }
3794  //Workaround for missing digest algorithms in old PHP & OpenSSL versions
3795  //@link http://stackoverflow.com/a/11117338/333340
3796  if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3797  in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3798  if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3799  openssl_pkey_free($privKey);
3800  return base64_encode($signature);
3801  }
3802  } else {
3803  $pinfo = openssl_pkey_get_details($privKey);
3804  $hash = hash('sha256', $signHeader);
3805  //'Magic' constant for SHA256 from RFC3447
3806  //@link https://tools.ietf.org/html/rfc3447#page-43
3807  $t = '3031300d060960864801650304020105000420' . $hash;
3808  $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3809  $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3810 
3811  if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3812  openssl_pkey_free($privKey);
3813  return base64_encode($signature);
3814  }
3815  }
3816  openssl_pkey_free($privKey);
3817  return '';
3818  }
3819 
3826  public function DKIM_HeaderC($signHeader)
3827  {
3828  $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3829  $lines = explode("\r\n", $signHeader);
3830  foreach ($lines as $key => $line) {
3831  list($heading, $value) = explode(':', $line, 2);
3832  $heading = strtolower($heading);
3833  $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
3834  $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3835  }
3836  $signHeader = implode("\r\n", $lines);
3837  return $signHeader;
3838  }
3839 
3846  public function DKIM_BodyC($body)
3847  {
3848  if ($body == '') {
3849  return "\r\n";
3850  }
3851  // stabilize line endings
3852  $body = str_replace("\r\n", "\n", $body);
3853  $body = str_replace("\n", "\r\n", $body);
3854  // END stabilize line endings
3855  while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3856  $body = substr($body, 0, strlen($body) - 2);
3857  }
3858  return $body;
3859  }
3860 
3869  public function DKIM_Add($headers_line, $subject, $body)
3870  {
3871  $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
3872  $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3873  $DKIMquery = 'dns/txt'; // Query method
3874  $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3875  $subject_header = "Subject: $subject";
3876  $headers = explode($this->LE, $headers_line);
3877  $from_header = '';
3878  $to_header = '';
3879  $date_header = '';
3880  $current = '';
3881  foreach ($headers as $header) {
3882  if (strpos($header, 'From:') === 0) {
3883  $from_header = $header;
3884  $current = 'from_header';
3885  } elseif (strpos($header, 'To:') === 0) {
3886  $to_header = $header;
3887  $current = 'to_header';
3888  } elseif (strpos($header, 'Date:') === 0) {
3889  $date_header = $header;
3890  $current = 'date_header';
3891  } else {
3892  if (!empty($$current) && strpos($header, ' =?') === 0) {
3893  $$current .= $header;
3894  } else {
3895  $current = '';
3896  }
3897  }
3898  }
3899  $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3900  $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3901  $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3902  $subject = str_replace(
3903  '|',
3904  '=7C',
3905  $this->DKIM_QP($subject_header)
3906  ); // Copied header fields (dkim-quoted-printable)
3907  $body = $this->DKIM_BodyC($body);
3908  $DKIMlen = strlen($body); // Length of body
3909  $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
3910  if ('' == $this->DKIM_identity) {
3911  $ident = '';
3912  } else {
3913  $ident = ' i=' . $this->DKIM_identity . ';';
3914  }
3915  $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3916  $DKIMsignatureType . '; q=' .
3917  $DKIMquery . '; l=' .
3918  $DKIMlen . '; s=' .
3919  $this->DKIM_selector .
3920  ";\r\n" .
3921  "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3922  "\th=From:To:Date:Subject;\r\n" .
3923  "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3924  "\tz=$from\r\n" .
3925  "\t|$to\r\n" .
3926  "\t|$date\r\n" .
3927  "\t|$subject;\r\n" .
3928  "\tbh=" . $DKIMb64 . ";\r\n" .
3929  "\tb=";
3930  $toSign = $this->DKIM_HeaderC(
3931  $from_header . "\r\n" .
3932  $to_header . "\r\n" .
3933  $date_header . "\r\n" .
3934  $subject_header . "\r\n" .
3935  $dkimhdrs
3936  );
3937  $signed = $this->DKIM_Sign($toSign);
3938  return $dkimhdrs . $signed . "\r\n";
3939  }
3940 
3947  public static function hasLineLongerThanMax($str)
3948  {
3949  //+2 to include CRLF line break for a 1000 total
3950  return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3951  }
3952 
3959  public function getToAddresses()
3960  {
3961  return $this->to;
3962  }
3963 
3970  public function getCcAddresses()
3971  {
3972  return $this->cc;
3973  }
3974 
3981  public function getBccAddresses()
3982  {
3983  return $this->bcc;
3984  }
3985 
3992  public function getReplyToAddresses()
3993  {
3994  return $this->ReplyTo;
3995  }
3996 
4003  public function getAllRecipientAddresses()
4004  {
4005  return $this->all_recipients;
4006  }
4007 
4018  protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4019  {
4020  if (!empty($this->action_function) && is_callable($this->action_function)) {
4021  $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4022  call_user_func_array($this->action_function, $params);
4023  }
4024  }
4025 }
4026 
4031 class phpmailerException extends Exception
4032 {
4037  public function errorMessage()
4038  {
4039  $errorMsg = '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
4040  return $errorMsg;
4041  }
4042 }
PHPMailer\encodeQPphp
encodeQPphp( $string, $line_max=76, $space_conv=false)
Definition: class.phpmailer.php:2926
PHPMailer\$mailHeader
$mailHeader
Definition: class.phpmailer.php:149
PHPMailer\getMailMIME
getMailMIME()
Definition: class.phpmailer.php:2124
PHPMailer\setError
setError($msg)
Definition: class.phpmailer.php:3246
PHPMailer\mb_pathinfo
static mb_pathinfo($path, $options=null)
Definition: class.phpmailer.php:3650
PHPMailer\getBccAddresses
getBccAddresses()
Definition: class.phpmailer.php:3981
PHPMailer\DKIM_Sign
DKIM_Sign($signHeader)
Definition: class.phpmailer.php:3780
PHPMailer\$sign_key_file
$sign_key_file
Definition: class.phpmailer.php:596
PHPMailer\normalizeBreaks
static normalizeBreaks($text, $breaktype="\r\n")
Definition: class.phpmailer.php:3732
PHPMailer\addBCC
addBCC($address, $name='')
Definition: class.phpmailer.php:841
PHPMailer\$SMTPKeepAlive
$SMTPKeepAlive
Definition: class.phpmailer.php:353
PHPMailer\$ReplyToQueue
$ReplyToQueue
Definition: class.phpmailer.php:533
PHPMailer\$validator
static $validator
Definition: class.phpmailer.php:467
PHPMailer\html2text
html2text($html, $advanced=false)
Definition: class.phpmailer.php:3494
PHPMailer\$Helo
$Helo
Definition: class.phpmailer.php:245
PHPMailer\$message_type
$message_type
Definition: class.phpmailer.php:561
PHPMailer\textLine
textLine($value)
Definition: class.phpmailer.php:2491
PHPMailer\$Mailer
$Mailer
Definition: class.phpmailer.php:163
PHPMailer\attachmentExists
attachmentExists()
Definition: class.phpmailer.php:3125
PHPMailer\getAttachments
getAttachments()
Definition: class.phpmailer.php:2551
PHPMailer\$SMTPOptions
$SMTPOptions
Definition: class.phpmailer.php:275
to
if the NMTOKENS definition is forced To get behavior of HTML Purifier prior to
Definition: Attr.ClassUseCDATA.txt:10
PHPMailer\clearAllRecipients
clearAllRecipients()
Definition: class.phpmailer.php:3213
PHPMailer\isShellSafe
static isShellSafe($string)
Definition: class.phpmailer.php:1439
Version
GNU LESSER GENERAL PUBLIC LICENSE Version
Definition: license.txt:2
PHPMailer\DKIM_QP
DKIM_QP($txt)
Definition: class.phpmailer.php:3759
PHPMailer\getSMTPInstance
getSMTPInstance()
Definition: class.phpmailer.php:1517
PHPMailer\_mime_types
static _mime_types($ext='')
Definition: class.phpmailer.php:3513
PHPMailer\$DKIM_identity
$DKIM_identity
Definition: class.phpmailer.php:404
PHPMailer\addEmbeddedImage
addEmbeddedImage($path, $cid, $name='', $encoding='base64', $type='', $disposition='inline')
Definition: class.phpmailer.php:3034
PHPMailer\encodeFile
encodeFile($path, $encoding='base64')
Definition: class.phpmailer.php:2689
PHPMailer\addrFormat
addrFormat($addr)
Definition: class.phpmailer.php:1839
PHPMailer\getToAddresses
getToAddresses()
Definition: class.phpmailer.php:3959
$ret
$ret
Definition: index.php:39
PHPMailer\$Body
$Body
Definition: class.phpmailer.php:109
PHPMailer\DKIM_Add
DKIM_Add($headers_line, $subject, $body)
Definition: class.phpmailer.php:3869
PHPMailer\isHTML
isHTML($isHtml=true)
Definition: class.phpmailer.php:752
PHPMailer\$ContentType
$ContentType
Definition: class.phpmailer.php:54
PHPMailer\$AllowEmpty
$AllowEmpty
Definition: class.phpmailer.php:383
PHPMailer\isSMTP
isSMTP()
Definition: class.phpmailer.php:765
PHPMailer\$MessageDate
$MessageDate
Definition: class.phpmailer.php:216
PHPMailer\lang
lang($key)
Definition: class.phpmailer.php:3308
PHPMailer\$PluginDir
$PluginDir
Definition: class.phpmailer.php:184
PHPMailer\$Encoding
$Encoding
Definition: class.phpmailer.php:61
$hash
$hash
Definition: Filter.ExtractStyleBlocks.txt:46
php
PHPMailer\$Workstation
$Workstation
Definition: class.phpmailer.php:308
PHPMailer\setLanguage
setLanguage($langcode='en', $lang_path='')
Definition: class.phpmailer.php:1741
PHPMailer\$to
$to
Definition: class.phpmailer.php:481
PHPMailer\$Sendmail
$Sendmail
Definition: class.phpmailer.php:169
PHPMailer\$From
$From
Definition: class.phpmailer.php:73
PHPMailer\send
send()
Definition: class.phpmailer.php:1207
PHPMailer\$MIMEHeader
$MIMEHeader
Definition: class.phpmailer.php:142
PHPMailer\$AuthType
$AuthType
Definition: class.phpmailer.php:294
PHPMailer\$SMTPDebug
$SMTPDebug
Definition: class.phpmailer.php:329
PHPMailer\$attachment
$attachment
Definition: class.phpmailer.php:540
PHPMailer\isSendmail
isSendmail()
Definition: class.phpmailer.php:783
PHPMailer\encodeString
encodeString($str, $encoding='base64')
Definition: class.phpmailer.php:2730
SMTP
Definition: class.smtp.php:28
PHPMailer\smtpClose
smtpClose()
Definition: class.phpmailer.php:1722
PHPMailer\$Password
$Password
Definition: class.phpmailer.php:287
PHPMailer\createBody
createBody()
Definition: class.phpmailer.php:2199
PHPMailer\$exceptions
$exceptions
Definition: class.phpmailer.php:618
PHPMailer\headerLine
headerLine($name, $value)
Definition: class.phpmailer.php:2480
PHPMailer\__destruct
__destruct()
Definition: class.phpmailer.php:667
PHPMailer\$UseSendmailOptions
$UseSendmailOptions
Definition: class.phpmailer.php:176
PHPMailer\wrapText
wrapText($message, $length, $qp_mode=false)
Definition: class.phpmailer.php:1861
PHPMailer\$language
$language
Definition: class.phpmailer.php:575
PHPMailer\$WordWrap
$WordWrap
Definition: class.phpmailer.php:156
PHPMailer\createHeader
createHeader()
Definition: class.phpmailer.php:2029
PHPMailer\addStringEmbeddedImage
addStringEmbeddedImage( $string, $cid, $name='', $encoding='base64', $type='', $disposition='inline')
Definition: class.phpmailer.php:3079
PHPMailer\$do_verp
$do_verp
Definition: class.phpmailer.php:377
PHPMailer\$Ical
$Ical
Definition: class.phpmailer.php:128
PHPMailer\STOP_CONTINUE
const STOP_CONTINUE
Definition: class.phpmailer.php:635
PHPMailer\rfcDate
static rfcDate()
Definition: class.phpmailer.php:3273
PHPMailer\setFrom
setFrom($address, $name='', $auto=true)
Definition: class.phpmailer.php:1011
$url
URI MungeSecretKey $url
Definition: URI.MungeSecretKey.txt:14
PHPMailer\$Priority
$Priority
Definition: class.phpmailer.php:42
PHPMailer\$RecipientsQueue
$RecipientsQueue
Definition: class.phpmailer.php:523
PHPMailer\clearCCs
clearCCs()
Definition: class.phpmailer.php:3177
PHPMailer\MAX_LINE_LENGTH
const MAX_LINE_LENGTH
Definition: class.phpmailer.php:651
PHPMailer\encodeQP
encodeQP($string, $line_max=76)
Definition: class.phpmailer.php:2901
PHPMailer\encodeHeader
encodeHeader($str, $position='text')
Definition: class.phpmailer.php:2766
PHPMailer\$AltBody
$AltBody
Definition: class.phpmailer.php:118
PHPMailer\$smtp
$smtp
Definition: class.phpmailer.php:474
PHPMailer\sign
sign($cert_filename, $key_filename, $key_pass, $extracerts_filename='')
Definition: class.phpmailer.php:3745
PHPMailer\addCC
addCC($address, $name='')
Definition: class.phpmailer.php:829
PHPMailer\getReplyToAddresses
getReplyToAddresses()
Definition: class.phpmailer.php:3992
PHPMailer\idnSupported
idnSupported()
Definition: class.phpmailer.php:1164
PHPMailer\$DKIM_domain
$DKIM_domain
Definition: class.phpmailer.php:418
PHPMailer\$lastMessageID
$lastMessageID
Definition: class.phpmailer.php:554
PHPMailer\sendmailSend
sendmailSend($header, $body)
Definition: class.phpmailer.php:1365
PHPMailer\addAnAddress
addAnAddress($kind, $address, $name='')
Definition: class.phpmailer.php:913
and
and
Definition: license.txt:18
PHPMailer\$Realm
$Realm
Definition: class.phpmailer.php:301
PHPMailer\$DKIM_selector
$DKIM_selector
Definition: class.phpmailer.php:397
PHPMailer\secureHeader
secureHeader($str)
Definition: class.phpmailer.php:3717
PHPMailer\STOP_MESSAGE
const STOP_MESSAGE
Definition: class.phpmailer.php:630
PHPMailer\addOrEnqueueAnAddress
addOrEnqueueAnAddress($kind, $address, $name)
Definition: class.phpmailer.php:869
PHPMailer\$CharSet
$CharSet
Definition: class.phpmailer.php:48
PHPMailer\$cc
$cc
Definition: class.phpmailer.php:488
phpmailerException\errorMessage
errorMessage()
Definition: class.phpmailer.php:4037
PHPMailer\smtpConnect
smtpConnect($options=null)
Definition: class.phpmailer.php:1600
PHPMailer\$FromName
$FromName
Definition: class.phpmailer.php:79
PHPMailer\$Timeout
$Timeout
Definition: class.phpmailer.php:315
PHPMailer\clearAddresses
clearAddresses()
Definition: class.phpmailer.php:3164
PHPMailer\base64EncodeWrapMB
base64EncodeWrapMB($str, $linebreak=null)
Definition: class.phpmailer.php:2859
PHPMailer\setMessageType
setMessageType()
Definition: class.phpmailer.php:2454
PHPMailer\smtpSend
smtpSend($header, $body)
Definition: class.phpmailer.php:1537
PHPMailer\attachAll
attachAll($disposition_type, $boundary)
Definition: class.phpmailer.php:2564
PHPMailer\$ReplyTo
$ReplyTo
Definition: class.phpmailer.php:502
PHPMailer\$Subject
$Subject
Definition: class.phpmailer.php:102
PHPMailer
PHPMailer\$XMailer
$XMailer
Definition: class.phpmailer.php:458
PHPMailer\$DKIM_private_string
$DKIM_private_string
Definition: class.phpmailer.php:431
PHPMailer\getAllRecipientAddresses
getAllRecipientAddresses()
Definition: class.phpmailer.php:4003
$path
$path
Definition: header.inc.php:12
PHPMailer\$SMTPAuth
$SMTPAuth
Definition: class.phpmailer.php:269
PHPMailer\$error_count
$error_count
Definition: class.phpmailer.php:582
PHPMailer\$ErrorInfo
$ErrorInfo
Definition: class.phpmailer.php:67
PHPMailer\$uniqueid
$uniqueid
Definition: class.phpmailer.php:625
PHPMailer\mailSend
mailSend($header, $body)
Definition: class.phpmailer.php:1473
PHPMailer\$SingleToArray
$SingleToArray
Definition: class.phpmailer.php:368
PHPMailer\isMail
isMail()
Definition: class.phpmailer.php:774
PHPMailer\preSend
preSend()
Definition: class.phpmailer.php:1229
PHPMailer\getTranslations
getTranslations()
Definition: class.phpmailer.php:1808
PHPMailer\$MIMEBody
$MIMEBody
Definition: class.phpmailer.php:135
PHPMailer\getSentMIMEMessage
getSentMIMEMessage()
Definition: class.phpmailer.php:2179
PHPMailer\$sign_key_pass
$sign_key_pass
Definition: class.phpmailer.php:611
PHPMailer\getLastMessageID
getLastMessageID()
Definition: class.phpmailer.php:1044
PHPMailer\filenameToType
static filenameToType($filename)
Definition: class.phpmailer.php:3628
PHPMailer\utf8CharBoundary
utf8CharBoundary($encodedText, $maxLength)
Definition: class.phpmailer.php:1960
time
that in the case of a Adaptation or at a minimum such credit will if a credit for all contributing authors of the Adaptation or Collection then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors For the avoidance of You may only use the credit required by this Section for the purpose of attribution in the manner set out above by exercising Your rights under this You may not implicitly or explicitly assert or imply any connection sponsorship or endorsement by the Original Licensor and or Attribution as of You or Your use of the without the express prior written permission of the Original Licensor and or Attribution Parties Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable if You Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or You must not modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author s honor or reputation Licensor agrees that in those in which any exercise of the right granted in modification or other derogatory action prejudicial to the Original Author s honor and the Licensor will waive or not as this to the fullest extent permitted by the applicable national to enable You to reasonably exercise Your right under Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN LICENSOR OFFERS THE WORK AS IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE STATUTORY OR WITHOUT WARRANTIES OF FITNESS FOR A PARTICULAR OR THE ABSENCE OF LATENT OR OTHER OR THE PRESENCE OF ABSENCE OF WHETHER OR NOT DISCOVERABLE SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED SO SUCH EXCLUSION MAY NOT APPLY TO YOU Limitation on Liability EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES Termination This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License Individuals or entities who have received Adaptations or Collections from You under this will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses and will survive any termination of this License Subject to the above terms and the license granted here is Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time
Definition: license.txt:56
PHPMailer\$bcc
$bcc
Definition: class.phpmailer.php:495
PHPMailer\generateId
generateId()
Definition: class.phpmailer.php:2188
PHPMailer\$Port
$Port
Definition: class.phpmailer.php:236
PHPMailer\addAddress
addAddress($address, $name='')
Definition: class.phpmailer.php:817
PHPMailer\$DKIM_private
$DKIM_private
Definition: class.phpmailer.php:424
PHPMailer\$boundary
$boundary
Definition: class.phpmailer.php:568
PHPMailer\CRLF
const CRLF
Definition: class.phpmailer.php:645
PHPMailer\$sign_extracerts_file
$sign_extracerts_file
Definition: class.phpmailer.php:603
PHPMailer\addAttachment
addAttachment($path, $name='', $encoding='base64', $type='', $disposition='attachment')
Definition: class.phpmailer.php:2508
PHPMailer\$Username
$Username
Definition: class.phpmailer.php:281
PHPMailer\clearReplyTos
clearReplyTos()
Definition: class.phpmailer.php:3203
PHPMailer\$DKIM_passphrase
$DKIM_passphrase
Definition: class.phpmailer.php:411
PHPMailer\$Hostname
$Hostname
Definition: class.phpmailer.php:199
PHPMailer\clearBCCs
clearBCCs()
Definition: class.phpmailer.php:3190
PHPMailer\$MessageID
$MessageID
Definition: class.phpmailer.php:209
PHPMailer\clearCustomHeaders
clearCustomHeaders()
Definition: class.phpmailer.php:3235
PHPMailer\serverHostname
serverHostname()
Definition: class.phpmailer.php:3287
PHPMailer\$all_recipients
$all_recipients
Definition: class.phpmailer.php:511
PHPMailer\$sign_cert_file
$sign_cert_file
Definition: class.phpmailer.php:589
PHPMailer\$SMTPAutoTLS
$SMTPAutoTLS
Definition: class.phpmailer.php:260
PHPMailer\$Sender
$Sender
Definition: class.phpmailer.php:86
PHPMailer\punyencodeAddress
punyencodeAddress($address)
Definition: class.phpmailer.php:1181
PHPMailer\endBoundary
endBoundary($boundary)
Definition: class.phpmailer.php:2443
PHPMailer\$Host
$Host
Definition: class.phpmailer.php:229
PHPMailer\hasLineLongerThanMax
static hasLineLongerThanMax($str)
Definition: class.phpmailer.php:3947
phpmailerException
Definition: class.phpmailer.php:4032
PHPMailer\$Debugoutput
$Debugoutput
Definition: class.phpmailer.php:345
PHPMailer\inlineImageExists
inlineImageExists()
Definition: class.phpmailer.php:3111
PHPMailer\msgHTML
msgHTML($message, $basedir='', $advanced=false)
Definition: class.phpmailer.php:3400
PHPMailer\isQmail
isQmail()
Definition: class.phpmailer.php:799
PHPMailer\$SMTPSecure
$SMTPSecure
Definition: class.phpmailer.php:252
PHPMailer\setWordWrap
setWordWrap()
Definition: class.phpmailer.php:2005
PHPMailer\doCallback
doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
Definition: class.phpmailer.php:4018
PHPMailer\$ReturnPath
$ReturnPath
Definition: class.phpmailer.php:96
PHPMailer\DKIM_BodyC
DKIM_BodyC($body)
Definition: class.phpmailer.php:3846
PHPMailer\$ConfirmReadingTo
$ConfirmReadingTo
Definition: class.phpmailer.php:190
PHPMailer\edebug
edebug($str)
Definition: class.phpmailer.php:711
PHPMailer\encodeQ
encodeQ($str, $position='text')
Definition: class.phpmailer.php:2942
PHPMailer\clearQueuedAddresses
clearQueuedAddresses($kind)
Definition: class.phpmailer.php:3150
PHPMailer\has8bitChars
has8bitChars($text)
Definition: class.phpmailer.php:2844
PHPMailer\$Version
$Version
Definition: class.phpmailer.php:34
PHPMailer\alternativeExists
alternativeExists()
Definition: class.phpmailer.php:3139
PHPMailer\$CustomHeader
$CustomHeader
Definition: class.phpmailer.php:547
PHPMailer\addrAppend
addrAppend($type, $addr)
Definition: class.phpmailer.php:1823
PHPMailer\parseAddresses
parseAddresses($addrstr, $useimap=true)
Definition: class.phpmailer.php:958
PHPMailer\validateAddress
static validateAddress($address, $patternselect=null)
Definition: class.phpmailer.php:1068
PHPMailer\addReplyTo
addReplyTo($address, $name='')
Definition: class.phpmailer.php:852
PHPMailer\$action_function
$action_function
Definition: class.phpmailer.php:451
$html
$html
Definition: Filter.ExtractStyleBlocks.txt:37
PHPMailer\fixEOL
fixEOL($str)
Definition: class.phpmailer.php:3345
PHPMailer\hasMultiBytes
hasMultiBytes($str)
Definition: class.phpmailer.php:2830
empty
Attr AllowedRel this is empty
Definition: Attr.AllowedRel.txt:7
PHPMailer\STOP_CRITICAL
const STOP_CRITICAL
Definition: class.phpmailer.php:640
PHPMailer\addCustomHeader
addCustomHeader($name, $value=null)
Definition: class.phpmailer.php:3365
PHPMailer\getCcAddresses
getCcAddresses()
Definition: class.phpmailer.php:3970
PHPMailer\getBoundary
getBoundary($boundary, $charSet, $contentType, $encoding)
Definition: class.phpmailer.php:2413
as
as
Definition: Filter.ExtractStyleBlocks.Escaping.txt:10
PHPMailer\getCustomHeaders
getCustomHeaders()
Definition: class.phpmailer.php:3379
PHPMailer\$LE
$LE
Definition: class.phpmailer.php:391
PHPMailer\DKIM_HeaderC
DKIM_HeaderC($signHeader)
Definition: class.phpmailer.php:3826
PHPMailer\clearAttachments
clearAttachments()
Definition: class.phpmailer.php:3226
PHPMailer\isError
isError()
Definition: class.phpmailer.php:3333
PHPMailer\addStringAttachment
addStringAttachment( $string, $filename, $encoding='base64', $type='', $disposition='attachment')
Definition: class.phpmailer.php:2993
or
Voluntary License Schemes The Licensor waives the right to collect whether individually or
Definition: license.txt:37
PHPMailer\postSend
postSend()
Definition: class.phpmailer.php:1326
PHPMailer\$SingleTo
$SingleTo
Definition: class.phpmailer.php:361
PHPMailer\__construct
__construct($exceptions=null)
Definition: class.phpmailer.php:657