[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> class-phpmailer.php (source)

   1  <?php
   2  /**
   3   * PHPMailer - PHP email creation and transport class.
   4   * PHP Version 5
   5   * @package PHPMailer
   6   * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
   7   * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
   8   * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
   9   * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  10   * @author Brent R. Matzelle (original founder)
  11   * @copyright 2012 - 2014 Marcus Bointon
  12   * @copyright 2010 - 2012 Jim Jagielski
  13   * @copyright 2004 - 2009 Andy Prevost
  14   * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  15   * @note This program is distributed in the hope that it will be useful - WITHOUT
  16   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17   * FITNESS FOR A PARTICULAR PURPOSE.
  18   */
  19  
  20  /**
  21   * PHPMailer - PHP email creation and transport class.
  22   * @package PHPMailer
  23   * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
  24   * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
  25   * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  26   * @author Brent R. Matzelle (original founder)
  27   */
  28  class PHPMailer
  29  {
  30      /**
  31       * The PHPMailer Version number.
  32       * @var string
  33       */
  34      public $Version = '5.2.22';
  35  
  36      /**
  37       * Email priority.
  38       * Options: null (default), 1 = High, 3 = Normal, 5 = low.
  39       * When null, the header is not set at all.
  40       * @var integer
  41       */
  42      public $Priority = null;
  43  
  44      /**
  45       * The character set of the message.
  46       * @var string
  47       */
  48      public $CharSet = 'iso-8859-1';
  49  
  50      /**
  51       * The MIME Content-type of the message.
  52       * @var string
  53       */
  54      public $ContentType = 'text/plain';
  55  
  56      /**
  57       * The message encoding.
  58       * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
  59       * @var string
  60       */
  61      public $Encoding = '8bit';
  62  
  63      /**
  64       * Holds the most recent mailer error message.
  65       * @var string
  66       */
  67      public $ErrorInfo = '';
  68  
  69      /**
  70       * The From email address for the message.
  71       * @var string
  72       */
  73      public $From = 'root@localhost';
  74  
  75      /**
  76       * The From name of the message.
  77       * @var string
  78       */
  79      public $FromName = 'Root User';
  80  
  81      /**
  82       * The Sender email (Return-Path) of the message.
  83       * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  84       * @var string
  85       */
  86      public $Sender = '';
  87  
  88      /**
  89       * The Return-Path of the message.
  90       * If empty, it will be set to either From or Sender.
  91       * @var string
  92       * @deprecated Email senders should never set a return-path header;
  93       * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
  94       * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
  95       */
  96      public $ReturnPath = '';
  97  
  98      /**
  99       * The Subject of the message.
 100       * @var string
 101       */
 102      public $Subject = '';
 103  
 104      /**
 105       * An HTML or plain text message body.
 106       * If HTML then call isHTML(true).
 107       * @var string
 108       */
 109      public $Body = '';
 110  
 111      /**
 112       * The plain-text message body.
 113       * This body can be read by mail clients that do not have HTML email
 114       * capability such as mutt & Eudora.
 115       * Clients that can read HTML will view the normal Body.
 116       * @var string
 117       */
 118      public $AltBody = '';
 119  
 120      /**
 121       * An iCal message part body.
 122       * Only supported in simple alt or alt_inline message types
 123       * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
 124       * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
 125       * @link http://kigkonsult.se/iCalcreator/
 126       * @var string
 127       */
 128      public $Ical = '';
 129  
 130      /**
 131       * The complete compiled MIME message body.
 132       * @access protected
 133       * @var string
 134       */
 135      protected $MIMEBody = '';
 136  
 137      /**
 138       * The complete compiled MIME message headers.
 139       * @var string
 140       * @access protected
 141       */
 142      protected $MIMEHeader = '';
 143  
 144      /**
 145       * Extra headers that createHeader() doesn't fold in.
 146       * @var string
 147       * @access protected
 148       */
 149      protected $mailHeader = '';
 150  
 151      /**
 152       * Word-wrap the message body to this number of chars.
 153       * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
 154       * @var integer
 155       */
 156      public $WordWrap = 0;
 157  
 158      /**
 159       * Which method to use to send mail.
 160       * Options: "mail", "sendmail", or "smtp".
 161       * @var string
 162       */
 163      public $Mailer = 'mail';
 164  
 165      /**
 166       * The path to the sendmail program.
 167       * @var string
 168       */
 169      public $Sendmail = '/usr/sbin/sendmail';
 170  
 171      /**
 172       * Whether mail() uses a fully sendmail-compatible MTA.
 173       * One which supports sendmail's "-oi -f" options.
 174       * @var boolean
 175       */
 176      public $UseSendmailOptions = true;
 177  
 178      /**
 179       * Path to PHPMailer plugins.
 180       * Useful if the SMTP class is not in the PHP include path.
 181       * @var string
 182       * @deprecated Should not be needed now there is an autoloader.
 183       */
 184      public $PluginDir = '';
 185  
 186      /**
 187       * The email address that a reading confirmation should be sent to, also known as read receipt.
 188       * @var string
 189       */
 190      public $ConfirmReadingTo = '';
 191  
 192      /**
 193       * The hostname to use in the Message-ID header and as default HELO string.
 194       * If empty, PHPMailer attempts to find one with, in order,
 195       * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
 196       * 'localhost.localdomain'.
 197       * @var string
 198       */
 199      public $Hostname = '';
 200  
 201      /**
 202       * An ID to be used in the Message-ID header.
 203       * If empty, a unique id will be generated.
 204       * You can set your own, but it must be in the format "<id@domain>",
 205       * as defined in RFC5322 section 3.6.4 or it will be ignored.
 206       * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
 207       * @var string
 208       */
 209      public $MessageID = '';
 210  
 211      /**
 212       * The message Date to be used in the Date header.
 213       * If empty, the current date will be added.
 214       * @var string
 215       */
 216      public $MessageDate = '';
 217  
 218      /**
 219       * SMTP hosts.
 220       * Either a single hostname or multiple semicolon-delimited hostnames.
 221       * You can also specify a different port
 222       * for each host by using this format: [hostname:port]
 223       * (e.g. "smtp1.example.com:25;smtp2.example.com").
 224       * You can also specify encryption type, for example:
 225       * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
 226       * Hosts will be tried in order.
 227       * @var string
 228       */
 229      public $Host = 'localhost';
 230  
 231      /**
 232       * The default SMTP server port.
 233       * @var integer
 234       * @TODO Why is this needed when the SMTP class takes care of it?
 235       */
 236      public $Port = 25;
 237  
 238      /**
 239       * The SMTP HELO of the message.
 240       * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
 241       * one with the same method described above for $Hostname.
 242       * @var string
 243       * @see PHPMailer::$Hostname
 244       */
 245      public $Helo = '';
 246  
 247      /**
 248       * What kind of encryption to use on the SMTP connection.
 249       * Options: '', 'ssl' or 'tls'
 250       * @var string
 251       */
 252      public $SMTPSecure = '';
 253  
 254      /**
 255       * Whether to enable TLS encryption automatically if a server supports it,
 256       * even if `SMTPSecure` is not set to 'tls'.
 257       * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
 258       * @var boolean
 259       */
 260      public $SMTPAutoTLS = true;
 261  
 262      /**
 263       * Whether to use SMTP authentication.
 264       * Uses the Username and Password properties.
 265       * @var boolean
 266       * @see PHPMailer::$Username
 267       * @see PHPMailer::$Password
 268       */
 269      public $SMTPAuth = false;
 270  
 271      /**
 272       * Options array passed to stream_context_create when connecting via SMTP.
 273       * @var array
 274       */
 275      public $SMTPOptions = array();
 276  
 277      /**
 278       * SMTP username.
 279       * @var string
 280       */
 281      public $Username = '';
 282  
 283      /**
 284       * SMTP password.
 285       * @var string
 286       */
 287      public $Password = '';
 288  
 289      /**
 290       * SMTP auth type.
 291       * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
 292       * @var string
 293       */
 294      public $AuthType = '';
 295  
 296      /**
 297       * SMTP realm.
 298       * Used for NTLM auth
 299       * @var string
 300       */
 301      public $Realm = '';
 302  
 303      /**
 304       * SMTP workstation.
 305       * Used for NTLM auth
 306       * @var string
 307       */
 308      public $Workstation = '';
 309  
 310      /**
 311       * The SMTP server timeout in seconds.
 312       * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
 313       * @var integer
 314       */
 315      public $Timeout = 300;
 316  
 317      /**
 318       * SMTP class debug output mode.
 319       * Debug output level.
 320       * Options:
 321       * * `0` No output
 322       * * `1` Commands
 323       * * `2` Data and commands
 324       * * `3` As 2 plus connection status
 325       * * `4` Low-level data output
 326       * @var integer
 327       * @see SMTP::$do_debug
 328       */
 329      public $SMTPDebug = 0;
 330  
 331      /**
 332       * How to handle debug output.
 333       * Options:
 334       * * `echo` Output plain-text as-is, appropriate for CLI
 335       * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
 336       * * `error_log` Output to error log as configured in php.ini
 337       *
 338       * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
 339       * <code>
 340       * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
 341       * </code>
 342       * @var string|callable
 343       * @see SMTP::$Debugoutput
 344       */
 345      public $Debugoutput = 'echo';
 346  
 347      /**
 348       * Whether to keep SMTP connection open after each message.
 349       * If this is set to true then to close the connection
 350       * requires an explicit call to smtpClose().
 351       * @var boolean
 352       */
 353      public $SMTPKeepAlive = false;
 354  
 355      /**
 356       * Whether to split multiple to addresses into multiple messages
 357       * or send them all in one message.
 358       * Only supported in `mail` and `sendmail` transports, not in SMTP.
 359       * @var boolean
 360       */
 361      public $SingleTo = false;
 362  
 363      /**
 364       * Storage for addresses when SingleTo is enabled.
 365       * @var array
 366       * @TODO This should really not be public
 367       */
 368      public $SingleToArray = array();
 369  
 370      /**
 371       * Whether to generate VERP addresses on send.
 372       * Only applicable when sending via SMTP.
 373       * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
 374       * @link http://www.postfix.org/VERP_README.html Postfix VERP info
 375       * @var boolean
 376       */
 377      public $do_verp = false;
 378  
 379      /**
 380       * Whether to allow sending messages with an empty body.
 381       * @var boolean
 382       */
 383      public $AllowEmpty = false;
 384  
 385      /**
 386       * The default line ending.
 387       * @note The default remains "\n". We force CRLF where we know
 388       *        it must be used via self::CRLF.
 389       * @var string
 390       */
 391      public $LE = "\n";
 392  
 393      /**
 394       * DKIM selector.
 395       * @var string
 396       */
 397      public $DKIM_selector = '';
 398  
 399      /**
 400       * DKIM Identity.
 401       * Usually the email address used as the source of the email.
 402       * @var string
 403       */
 404      public $DKIM_identity = '';
 405  
 406      /**
 407       * DKIM passphrase.
 408       * Used if your key is encrypted.
 409       * @var string
 410       */
 411      public $DKIM_passphrase = '';
 412  
 413      /**
 414       * DKIM signing domain name.
 415       * @example 'example.com'
 416       * @var string
 417       */
 418      public $DKIM_domain = '';
 419  
 420      /**
 421       * DKIM private key file path.
 422       * @var string
 423       */
 424      public $DKIM_private = '';
 425  
 426      /**
 427       * DKIM private key string.
 428       * If set, takes precedence over `$DKIM_private`.
 429       * @var string
 430       */
 431      public $DKIM_private_string = '';
 432  
 433      /**
 434       * Callback Action function name.
 435       *
 436       * The function that handles the result of the send email action.
 437       * It is called out by send() for each email sent.
 438       *
 439       * Value can be any php callable: http://www.php.net/is_callable
 440       *
 441       * Parameters:
 442       *   boolean $result        result of the send action
 443       *   string  $to            email address of the recipient
 444       *   string  $cc            cc email addresses
 445       *   string  $bcc           bcc email addresses
 446       *   string  $subject       the subject
 447       *   string  $body          the email body
 448       *   string  $from          email address of sender
 449       * @var string
 450       */
 451      public $action_function = '';
 452  
 453      /**
 454       * What to put in the X-Mailer header.
 455       * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
 456       * @var string
 457       */
 458      public $XMailer = '';
 459  
 460      /**
 461       * Which validator to use by default when validating email addresses.
 462       * May be a callable to inject your own validator, but there are several built-in validators.
 463       * @see PHPMailer::validateAddress()
 464       * @var string|callable
 465       * @static
 466       */
 467      public static $validator = 'auto';
 468  
 469      /**
 470       * An instance of the SMTP sender class.
 471       * @var SMTP
 472       * @access protected
 473       */
 474      protected $smtp = null;
 475  
 476      /**
 477       * The array of 'to' names and addresses.
 478       * @var array
 479       * @access protected
 480       */
 481      protected $to = array();
 482  
 483      /**
 484       * The array of 'cc' names and addresses.
 485       * @var array
 486       * @access protected
 487       */
 488      protected $cc = array();
 489  
 490      /**
 491       * The array of 'bcc' names and addresses.
 492       * @var array
 493       * @access protected
 494       */
 495      protected $bcc = array();
 496  
 497      /**
 498       * The array of reply-to names and addresses.
 499       * @var array
 500       * @access protected
 501       */
 502      protected $ReplyTo = array();
 503  
 504      /**
 505       * An array of all kinds of addresses.
 506       * Includes all of $to, $cc, $bcc
 507       * @var array
 508       * @access protected
 509       * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
 510       */
 511      protected $all_recipients = array();
 512  
 513      /**
 514       * An array of names and addresses queued for validation.
 515       * In send(), valid and non duplicate entries are moved to $all_recipients
 516       * and one of $to, $cc, or $bcc.
 517       * This array is used only for addresses with IDN.
 518       * @var array
 519       * @access protected
 520       * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
 521       * @see PHPMailer::$all_recipients
 522       */
 523      protected $RecipientsQueue = array();
 524  
 525      /**
 526       * An array of reply-to names and addresses queued for validation.
 527       * In send(), valid and non duplicate entries are moved to $ReplyTo.
 528       * This array is used only for addresses with IDN.
 529       * @var array
 530       * @access protected
 531       * @see PHPMailer::$ReplyTo
 532       */
 533      protected $ReplyToQueue = array();
 534  
 535      /**
 536       * The array of attachments.
 537       * @var array
 538       * @access protected
 539       */
 540      protected $attachment = array();
 541  
 542      /**
 543       * The array of custom headers.
 544       * @var array
 545       * @access protected
 546       */
 547      protected $CustomHeader = array();
 548  
 549      /**
 550       * The most recent Message-ID (including angular brackets).
 551       * @var string
 552       * @access protected
 553       */
 554      protected $lastMessageID = '';
 555  
 556      /**
 557       * The message's MIME type.
 558       * @var string
 559       * @access protected
 560       */
 561      protected $message_type = '';
 562  
 563      /**
 564       * The array of MIME boundary strings.
 565       * @var array
 566       * @access protected
 567       */
 568      protected $boundary = array();
 569  
 570      /**
 571       * The array of available languages.
 572       * @var array
 573       * @access protected
 574       */
 575      protected $language = array();
 576  
 577      /**
 578       * The number of errors encountered.
 579       * @var integer
 580       * @access protected
 581       */
 582      protected $error_count = 0;
 583  
 584      /**
 585       * The S/MIME certificate file path.
 586       * @var string
 587       * @access protected
 588       */
 589      protected $sign_cert_file = '';
 590  
 591      /**
 592       * The S/MIME key file path.
 593       * @var string
 594       * @access protected
 595       */
 596      protected $sign_key_file = '';
 597  
 598      /**
 599       * The optional S/MIME extra certificates ("CA Chain") file path.
 600       * @var string
 601       * @access protected
 602       */
 603      protected $sign_extracerts_file = '';
 604  
 605      /**
 606       * The S/MIME password for the key.
 607       * Used only if the key is encrypted.
 608       * @var string
 609       * @access protected
 610       */
 611      protected $sign_key_pass = '';
 612  
 613      /**
 614       * Whether to throw exceptions for errors.
 615       * @var boolean
 616       * @access protected
 617       */
 618      protected $exceptions = false;
 619  
 620      /**
 621       * Unique ID used for message ID and boundaries.
 622       * @var string
 623       * @access protected
 624       */
 625      protected $uniqueid = '';
 626  
 627      /**
 628       * Error severity: message only, continue processing.
 629       */
 630      const STOP_MESSAGE = 0;
 631  
 632      /**
 633       * Error severity: message, likely ok to continue processing.
 634       */
 635      const STOP_CONTINUE = 1;
 636  
 637      /**
 638       * Error severity: message, plus full stop, critical error reached.
 639       */
 640      const STOP_CRITICAL = 2;
 641  
 642      /**
 643       * SMTP RFC standard line ending.
 644       */
 645      const CRLF = "\r\n";
 646  
 647      /**
 648       * The maximum line length allowed by RFC 2822 section 2.1.1
 649       * @var integer
 650       */
 651      const MAX_LINE_LENGTH = 998;
 652  
 653      /**
 654       * Constructor.
 655       * @param boolean $exceptions Should we throw external exceptions?
 656       */
 657      public function __construct($exceptions = null)
 658      {
 659          if ($exceptions !== null) {
 660              $this->exceptions = (boolean)$exceptions;
 661          }
 662      }
 663  
 664      /**
 665       * Destructor.
 666       */
 667      public function __destruct()
 668      {
 669          //Close any open SMTP connection nicely
 670          $this->smtpClose();
 671      }
 672  
 673      /**
 674       * Call mail() in a safe_mode-aware fashion.
 675       * Also, unless sendmail_path points to sendmail (or something that
 676       * claims to be sendmail), don't pass params (not a perfect fix,
 677       * but it will do)
 678       * @param string $to To
 679       * @param string $subject Subject
 680       * @param string $body Message Body
 681       * @param string $header Additional Header(s)
 682       * @param string $params Params
 683       * @access private
 684       * @return boolean
 685       */
 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      }
 704      /**
 705       * Output debugging info via user-defined method.
 706       * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
 707       * @see PHPMailer::$Debugoutput
 708       * @see PHPMailer::$SMTPDebug
 709       * @param string $str
 710       */
 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  
 747      /**
 748       * Sets message type to HTML or plain.
 749       * @param boolean $isHtml True for HTML mode.
 750       * @return void
 751       */
 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  
 761      /**
 762       * Send messages using SMTP.
 763       * @return void
 764       */
 765      public function isSMTP()
 766      {
 767          $this->Mailer = 'smtp';
 768      }
 769  
 770      /**
 771       * Send messages using PHP's mail() function.
 772       * @return void
 773       */
 774      public function isMail()
 775      {
 776          $this->Mailer = 'mail';
 777      }
 778  
 779      /**
 780       * Send messages using $Sendmail.
 781       * @return void
 782       */
 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  
 795      /**
 796       * Send messages using qmail.
 797       * @return void
 798       */
 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  
 811      /**
 812       * Add a "To" address.
 813       * @param string $address The email address to send to
 814       * @param string $name
 815       * @return boolean true on success, false if address already used or invalid in some way
 816       */
 817      public function addAddress($address, $name = '')
 818      {
 819          return $this->addOrEnqueueAnAddress('to', $address, $name);
 820      }
 821  
 822      /**
 823       * Add a "CC" address.
 824       * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 825       * @param string $address The email address to send to
 826       * @param string $name
 827       * @return boolean true on success, false if address already used or invalid in some way
 828       */
 829      public function addCC($address, $name = '')
 830      {
 831          return $this->addOrEnqueueAnAddress('cc', $address, $name);
 832      }
 833  
 834      /**
 835       * Add a "BCC" address.
 836       * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
 837       * @param string $address The email address to send to
 838       * @param string $name
 839       * @return boolean true on success, false if address already used or invalid in some way
 840       */
 841      public function addBCC($address, $name = '')
 842      {
 843          return $this->addOrEnqueueAnAddress('bcc', $address, $name);
 844      }
 845  
 846      /**
 847       * Add a "Reply-To" address.
 848       * @param string $address The email address to reply to
 849       * @param string $name
 850       * @return boolean true on success, false if address already used or invalid in some way
 851       */
 852      public function addReplyTo($address, $name = '')
 853      {
 854          return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
 855      }
 856  
 857      /**
 858       * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
 859       * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
 860       * be modified after calling this function), addition of such addresses is delayed until send().
 861       * Addresses that have been added already return false, but do not throw exceptions.
 862       * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 863       * @param string $address The email address to send, resp. to reply to
 864       * @param string $name
 865       * @throws phpmailerException
 866       * @return boolean true on success, false if address already used or invalid in some way
 867       * @access protected
 868       */
 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  
 903      /**
 904       * Add an address to one of the recipient arrays or to the ReplyTo array.
 905       * Addresses that have been added already return false, but do not throw exceptions.
 906       * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
 907       * @param string $address The email address to send, resp. to reply to
 908       * @param string $name
 909       * @throws phpmailerException
 910       * @return boolean true on success, false if address already used or invalid in some way
 911       * @access protected
 912       */
 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  
 948      /**
 949       * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
 950       * of the form "display name <address>" into an array of name/address pairs.
 951       * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
 952       * Note that quotes in the name part are removed.
 953       * @param string $addrstr The address list string
 954       * @param bool $useimap Whether to use the IMAP extension to parse the list
 955       * @return array
 956       * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
 957       */
 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  
1003      /**
1004       * Set the From and FromName properties.
1005       * @param string $address
1006       * @param string $name
1007       * @param boolean $auto Whether to also set the Sender address, defaults to true
1008       * @throws phpmailerException
1009       * @return boolean
1010       */
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  
1037      /**
1038       * Return the Message-ID header of the last email.
1039       * Technically this is the value from the last time the headers were created,
1040       * but it's also the message ID of the last sent message except in
1041       * pathological cases.
1042       * @return string
1043       */
1044      public function getLastMessageID()
1045      {
1046          return $this->lastMessageID;
1047      }
1048  
1049      /**
1050       * Check that a string looks like an email address.
1051       * @param string $address The email address to check
1052       * @param string|callable $patternselect A selector for the validation pattern to use :
1053       * * `auto` Pick best pattern automatically;
1054       * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1055       * * `pcre` Use old PCRE implementation;
1056       * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1057       * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1058       * * `noregex` Don't use a regex: super fast, really dumb.
1059       * Alternatively you may pass in a callable to inject your own validator, for example:
1060       * PHPMailer::validateAddress('user@example.com', function($address) {
1061       *     return (strpos($address, '@') !== false);
1062       * });
1063       * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
1064       * @return boolean
1065       * @static
1066       * @access public
1067       */
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':
1104                  /**
1105                   * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1106                   * @link http://squiloople.com/2009/12/20/email-address-validation/
1107                   * @copyright 2009-2010 Michael Rushton
1108                   * Feel free to use and redistribute this code. But please keep this copyright notice.
1109                   */
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':
1138                  /**
1139                   * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1140                   * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1141                   */
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  
1159      /**
1160       * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1161       * "intl" and "mbstring" PHP extensions.
1162       * @return bool "true" if required functions for IDN support are present
1163       */
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  
1170      /**
1171       * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1172       * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1173       * This function silently returns unmodified address if:
1174       * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1175       * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1176       *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
1177       * @see PHPMailer::$CharSet
1178       * @param string $address The email address to convert
1179       * @return string The encoded address in ASCII form
1180       */
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  
1201      /**
1202       * Create a message and send it.
1203       * Uses the sending method specified by $Mailer.
1204       * @throws phpmailerException
1205       * @return boolean false on error - See the ErrorInfo property for details of the error.
1206       */
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  
1224      /**
1225       * Prepare a message for sending.
1226       * @throws phpmailerException
1227       * @return boolean
1228       */
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  
1320      /**
1321       * Actually send a message.
1322       * Send the email via the selected mechanism
1323       * @throws phpmailerException
1324       * @return boolean
1325       */
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  
1356      /**
1357       * Send mail using the $Sendmail program.
1358       * @param string $header The message headers
1359       * @param string $body The message body
1360       * @see PHPMailer::$Sendmail
1361       * @throws phpmailerException
1362       * @access protected
1363       * @return boolean
1364       */
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  
1430      /**
1431       * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
1432       *
1433       * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
1434       * @param string $string The string to be validated
1435       * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
1436       * @access protected
1437       * @return boolean
1438       */
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  
1464      /**
1465       * Send mail using the PHP mail() function.
1466       * @param string $header The message headers
1467       * @param string $body The message body
1468       * @link http://www.php.net/manual/en/book.mail.php
1469       * @throws phpmailerException
1470       * @access protected
1471       * @return boolean
1472       */
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  
1512      /**
1513       * Get an instance to use for SMTP operations.
1514       * Override this function to load your own SMTP implementation
1515       * @return SMTP
1516       */
1517      public function getSMTPInstance()
1518      {
1519          if (!is_object($this->smtp)) {
1520              require_once ( 'class-smtp.php' );
1521              $this->smtp = new SMTP;
1522          }
1523          return $this->smtp;
1524      }
1525  
1526      /**
1527       * Send mail via SMTP.
1528       * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1529       * Uses the PHPMailerSMTP class by default.
1530       * @see PHPMailer::getSMTPInstance() to use a different class.
1531       * @param string $header The message headers
1532       * @param string $body The message body
1533       * @throws phpmailerException
1534       * @uses SMTP
1535       * @access protected
1536       * @return boolean
1537       */
1538      protected function smtpSend($header, $body)
1539      {
1540          $bad_rcpt = array();
1541          if (!$this->smtpConnect($this->SMTPOptions)) {
1542              throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1543          }
1544          if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1545              $smtp_from = $this->Sender;
1546          } else {
1547              $smtp_from = $this->From;
1548          }
1549          if (!$this->smtp->mail($smtp_from)) {
1550              $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1551              throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1552          }
1553  
1554          // Attempt to send to all recipients
1555          foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1556              foreach ($togroup as $to) {
1557                  if (!$this->smtp->recipient($to[0])) {
1558                      $error = $this->smtp->getError();
1559                      $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1560                      $isSent = false;
1561                  } else {
1562                      $isSent = true;
1563                  }
1564                  $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1565              }
1566          }
1567  
1568          // Only send the DATA command if we have viable recipients
1569          if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1570              throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1571          }
1572          if ($this->SMTPKeepAlive) {
1573              $this->smtp->reset();
1574          } else {
1575              $this->smtp->quit();
1576              $this->smtp->close();
1577          }
1578          //Create error message for any bad addresses
1579          if (count($bad_rcpt) > 0) {
1580              $errstr = '';
1581              foreach ($bad_rcpt as $bad) {
1582                  $errstr .= $bad['to'] . ': ' . $bad['error'];
1583              }
1584              throw new phpmailerException(
1585                  $this->lang('recipients_failed') . $errstr,
1586                  self::STOP_CONTINUE
1587              );
1588          }
1589          return true;
1590      }
1591  
1592      /**
1593       * Initiate a connection to an SMTP server.
1594       * Returns false if the operation failed.
1595       * @param array $options An array of options compatible with stream_context_create()
1596       * @uses SMTP
1597       * @access public
1598       * @throws phpmailerException
1599       * @return boolean
1600       */
1601      public function smtpConnect($options = null)
1602      {
1603          if (is_null($this->smtp)) {
1604              $this->smtp = $this->getSMTPInstance();
1605          }
1606  
1607          //If no options are provided, use whatever is set in the instance
1608          if (is_null($options)) {
1609              $options = $this->SMTPOptions;
1610          }
1611  
1612          // Already connected?
1613          if ($this->smtp->connected()) {
1614              return true;
1615          }
1616  
1617          $this->smtp->setTimeout($this->Timeout);
1618          $this->smtp->setDebugLevel($this->SMTPDebug);
1619          $this->smtp->setDebugOutput($this->Debugoutput);
1620          $this->smtp->setVerp($this->do_verp);
1621          $hosts = explode(';', $this->Host);
1622          $lastexception = null;
1623  
1624          foreach ($hosts as $hostentry) {
1625              $hostinfo = array();
1626              if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1627                  // Not a valid host entry
1628                  continue;
1629              }
1630              // $hostinfo[2]: optional ssl or tls prefix
1631              // $hostinfo[3]: the hostname
1632              // $hostinfo[4]: optional port number
1633              // The host string prefix can temporarily override the current setting for SMTPSecure
1634              // If it's not specified, the default value is used
1635              $prefix = '';
1636              $secure = $this->SMTPSecure;
1637              $tls = ($this->SMTPSecure == 'tls');
1638              if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1639                  $prefix = 'ssl://';
1640                  $tls = false; // Can't have SSL and TLS at the same time
1641                  $secure = 'ssl';
1642              } elseif ($hostinfo[2] == 'tls') {
1643                  $tls = true;
1644                  // tls doesn't use a prefix
1645                  $secure = 'tls';
1646              }
1647              //Do we need the OpenSSL extension?
1648              $sslext = defined('OPENSSL_ALGO_SHA1');
1649              if ('tls' === $secure or 'ssl' === $secure) {
1650                  //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1651                  if (!$sslext) {
1652                      throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1653                  }
1654              }
1655              $host = $hostinfo[3];
1656              $port = $this->Port;
1657              $tport = (integer)$hostinfo[4];
1658              if ($tport > 0 and $tport < 65536) {
1659                  $port = $tport;
1660              }
1661              if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1662                  try {
1663                      if ($this->Helo) {
1664                          $hello = $this->Helo;
1665                      } else {
1666                          $hello = $this->serverHostname();
1667                      }
1668                      $this->smtp->hello($hello);
1669                      //Automatically enable TLS encryption if:
1670                      // * it's not disabled
1671                      // * we have openssl extension
1672                      // * we are not already using SSL
1673                      // * the server offers STARTTLS
1674                      if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1675                          $tls = true;
1676                      }
1677                      if ($tls) {
1678                          if (!$this->smtp->startTLS()) {
1679                              throw new phpmailerException($this->lang('connect_host'));
1680                          }
1681                          // We must resend EHLO after TLS negotiation
1682                          $this->smtp->hello($hello);
1683                      }
1684                      if ($this->SMTPAuth) {
1685                          if (!$this->smtp->authenticate(
1686                              $this->Username,
1687                              $this->Password,
1688                              $this->AuthType,
1689                              $this->Realm,
1690                              $this->Workstation
1691                          )
1692                          ) {
1693                              throw new phpmailerException($this->lang('authenticate'));
1694                          }
1695                      }
1696                      return true;
1697                  } catch (phpmailerException $exc) {
1698                      $lastexception = $exc;
1699                      $this->edebug($exc->getMessage());
1700                      // We must have connected, but then failed TLS or Auth, so close connection nicely
1701                      $this->smtp->quit();
1702                  }
1703              }
1704          }
1705          // If we get here, all connection attempts have failed, so close connection hard
1706          $this->smtp->close();
1707          // As we've caught all exceptions, just report whatever the last one was
1708          if ($this->exceptions and !is_null($lastexception)) {
1709              throw $lastexception;
1710          }
1711          return false;
1712      }
1713  
1714      /**
1715       * Close the active SMTP session if one exists.
1716       * @return void
1717       */
1718      public function smtpClose()
1719      {
1720          if (is_a($this->smtp, 'SMTP')) {
1721              if ($this->smtp->connected()) {
1722                  $this->smtp->quit();
1723                  $this->smtp->close();
1724              }
1725          }
1726      }
1727  
1728      /**
1729       * Set the language for error messages.
1730       * Returns false if it cannot load the language file.
1731       * The default language is English.
1732       * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1733       * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1734       * @return boolean
1735       * @access public
1736       */
1737      public function setLanguage($langcode = 'en', $lang_path = '')
1738      {
1739          // Backwards compatibility for renamed language codes
1740          $renamed_langcodes = array(
1741              'br' => 'pt_br',
1742              'cz' => 'cs',
1743              'dk' => 'da',
1744              'no' => 'nb',
1745              'se' => 'sv',
1746          );
1747  
1748          if (isset($renamed_langcodes[$langcode])) {
1749              $langcode = $renamed_langcodes[$langcode];
1750          }
1751  
1752          // Define full set of translatable strings in English
1753          $PHPMAILER_LANG = array(
1754              'authenticate' => 'SMTP Error: Could not authenticate.',
1755              'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1756              'data_not_accepted' => 'SMTP Error: data not accepted.',
1757              'empty_message' => 'Message body empty',
1758              'encoding' => 'Unknown encoding: ',
1759              'execute' => 'Could not execute: ',
1760              'file_access' => 'Could not access file: ',
1761              'file_open' => 'File Error: Could not open file: ',
1762              'from_failed' => 'The following From address failed: ',
1763              'instantiate' => 'Could not instantiate mail function.',
1764              'invalid_address' => 'Invalid address: ',
1765              'mailer_not_supported' => ' mailer is not supported.',
1766              'provide_address' => 'You must provide at least one recipient email address.',
1767              'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1768              'signing' => 'Signing Error: ',
1769              'smtp_connect_failed' => 'SMTP connect() failed.',
1770              'smtp_error' => 'SMTP server error: ',
1771              'variable_set' => 'Cannot set or reset variable: ',
1772              'extension_missing' => 'Extension missing: '
1773          );
1774          if (empty($lang_path)) {
1775              // Calculate an absolute path so it can work if CWD is not here
1776              $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1777          }
1778          //Validate $langcode
1779          if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
1780              $langcode = 'en';
1781          }
1782          $foundlang = true;
1783          $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1784          // There is no English translation file
1785          if ($langcode != 'en') {
1786              // Make sure language file path is readable
1787              if (!is_readable($lang_file)) {
1788                  $foundlang = false;
1789              } else {
1790                  // Overwrite language-specific strings.
1791                  // This way we'll never have missing translation keys.
1792                  $foundlang = include $lang_file;
1793              }
1794          }
1795          $this->language = $PHPMAILER_LANG;
1796          return (boolean)$foundlang; // Returns false if language not found
1797      }
1798  
1799      /**
1800       * Get the array of strings for the current language.
1801       * @return array
1802       */
1803      public function getTranslations()
1804      {
1805          return $this->language;
1806      }
1807  
1808      /**
1809       * Create recipient headers.
1810       * @access public
1811       * @param string $type
1812       * @param array $addr An array of recipient,
1813       * where each recipient is a 2-element indexed array with element 0 containing an address
1814       * and element 1 containing a name, like:
1815       * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1816       * @return string
1817       */
1818      public function addrAppend($type, $addr)
1819      {
1820          $addresses = array();
1821          foreach ($addr as $address) {
1822              $addresses[] = $this->addrFormat($address);
1823          }
1824          return $type . ': ' . implode(', ', $addresses) . $this->LE;
1825      }
1826  
1827      /**
1828       * Format an address for use in a message header.
1829       * @access public
1830       * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1831       *      like array('joe@example.com', 'Joe User')
1832       * @return string
1833       */
1834      public function addrFormat($addr)
1835      {
1836          if (empty($addr[1])) { // No name provided
1837              return $this->secureHeader($addr[0]);
1838          } else {
1839              return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1840                  $addr[0]
1841              ) . '>';
1842          }
1843      }
1844  
1845      /**
1846       * Word-wrap message.
1847       * For use with mailers that do not automatically perform wrapping
1848       * and for quoted-printable encoded messages.
1849       * Original written by philippe.
1850       * @param string $message The message to wrap
1851       * @param integer $length The line length to wrap to
1852       * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1853       * @access public
1854       * @return string
1855       */
1856      public function wrapText($message, $length, $qp_mode = false)
1857      {
1858          if ($qp_mode) {
1859              $soft_break = sprintf(' =%s', $this->LE);
1860          } else {
1861              $soft_break = $this->LE;
1862          }
1863          // If utf-8 encoding is used, we will need to make sure we don't
1864          // split multibyte characters when we wrap
1865          $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1866          $lelen = strlen($this->LE);
1867          $crlflen = strlen(self::CRLF);
1868  
1869          $message = $this->fixEOL($message);
1870          //Remove a trailing line break
1871          if (substr($message, -$lelen) == $this->LE) {
1872              $message = substr($message, 0, -$lelen);
1873          }
1874  
1875          //Split message into lines
1876          $lines = explode($this->LE, $message);
1877          //Message will be rebuilt in here
1878          $message = '';
1879          foreach ($lines as $line) {
1880              $words = explode(' ', $line);
1881              $buf = '';
1882              $firstword = true;
1883              foreach ($words as $word) {
1884                  if ($qp_mode and (strlen($word) > $length)) {
1885                      $space_left = $length - strlen($buf) - $crlflen;
1886                      if (!$firstword) {
1887                          if ($space_left > 20) {
1888                              $len = $space_left;
1889                              if ($is_utf8) {
1890                                  $len = $this->utf8CharBoundary($word, $len);
1891                              } elseif (substr($word, $len - 1, 1) == '=') {
1892                                  $len--;
1893                              } elseif (substr($word, $len - 2, 1) == '=') {
1894                                  $len -= 2;
1895                              }
1896                              $part = substr($word, 0, $len);
1897                              $word = substr($word, $len);
1898                              $buf .= ' ' . $part;
1899                              $message .= $buf . sprintf('=%s', self::CRLF);
1900                          } else {
1901                              $message .= $buf . $soft_break;
1902                          }
1903                          $buf = '';
1904                      }
1905                      while (strlen($word) > 0) {
1906                          if ($length <= 0) {
1907                              break;
1908                          }
1909                          $len = $length;
1910                          if ($is_utf8) {
1911                              $len = $this->utf8CharBoundary($word, $len);
1912                          } elseif (substr($word, $len - 1, 1) == '=') {
1913                              $len--;
1914                          } elseif (substr($word, $len - 2, 1) == '=') {
1915                              $len -= 2;
1916                          }
1917                          $part = substr($word, 0, $len);
1918                          $word = substr($word, $len);
1919  
1920                          if (strlen($word) > 0) {
1921                              $message .= $part . sprintf('=%s', self::CRLF);
1922                          } else {
1923                              $buf = $part;
1924                          }
1925                      }
1926                  } else {
1927                      $buf_o = $buf;
1928                      if (!$firstword) {
1929                          $buf .= ' ';
1930                      }
1931                      $buf .= $word;
1932  
1933                      if (strlen($buf) > $length and $buf_o != '') {
1934                          $message .= $buf_o . $soft_break;
1935                          $buf = $word;
1936                      }
1937                  }
1938                  $firstword = false;
1939              }
1940              $message .= $buf . self::CRLF;
1941          }
1942  
1943          return $message;
1944      }
1945  
1946      /**
1947       * Find the last character boundary prior to $maxLength in a utf-8
1948       * quoted-printable encoded string.
1949       * Original written by Colin Brown.
1950       * @access public
1951       * @param string $encodedText utf-8 QP text
1952       * @param integer $maxLength Find the last character boundary prior to this length
1953       * @return integer
1954       */
1955      public function utf8CharBoundary($encodedText, $maxLength)
1956      {
1957          $foundSplitPos = false;
1958          $lookBack = 3;
1959          while (!$foundSplitPos) {
1960              $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1961              $encodedCharPos = strpos($lastChunk, '=');
1962              if (false !== $encodedCharPos) {
1963                  // Found start of encoded character byte within $lookBack block.
1964                  // Check the encoded byte value (the 2 chars after the '=')
1965                  $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1966                  $dec = hexdec($hex);
1967                  if ($dec < 128) {
1968                      // Single byte character.
1969                      // If the encoded char was found at pos 0, it will fit
1970                      // otherwise reduce maxLength to start of the encoded char
1971                      if ($encodedCharPos > 0) {
1972                          $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1973                      }
1974                      $foundSplitPos = true;
1975                  } elseif ($dec >= 192) {
1976                      // First byte of a multi byte character
1977                      // Reduce maxLength to split at start of character
1978                      $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1979                      $foundSplitPos = true;
1980                  } elseif ($dec < 192) {
1981                      // Middle byte of a multi byte character, look further back
1982                      $lookBack += 3;
1983                  }
1984              } else {
1985                  // No encoded character found
1986                  $foundSplitPos = true;
1987              }
1988          }
1989          return $maxLength;
1990      }
1991  
1992      /**
1993       * Apply word wrapping to the message body.
1994       * Wraps the message body to the number of chars set in the WordWrap property.
1995       * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1996       * This is called automatically by createBody(), so you don't need to call it yourself.
1997       * @access public
1998       * @return void
1999       */
2000      public function setWordWrap()
2001      {
2002          if ($this->WordWrap < 1) {
2003              return;
2004          }
2005  
2006          switch ($this->message_type) {
2007              case 'alt':
2008              case 'alt_inline':
2009              case 'alt_attach':
2010              case 'alt_inline_attach':
2011                  $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
2012                  break;
2013              default:
2014                  $this->Body = $this->wrapText($this->Body, $this->WordWrap);
2015                  break;
2016          }
2017      }
2018  
2019      /**
2020       * Assemble message headers.
2021       * @access public
2022       * @return string The assembled headers
2023       */
2024      public function createHeader()
2025      {
2026          $result = '';
2027  
2028          if ($this->MessageDate == '') {
2029              $this->MessageDate = self::rfcDate();
2030          }
2031          $result .= $this->headerLine('Date', $this->MessageDate);
2032  
2033          // To be created automatically by mail()
2034          if ($this->SingleTo) {
2035              if ($this->Mailer != 'mail') {
2036                  foreach ($this->to as $toaddr) {
2037                      $this->SingleToArray[] = $this->addrFormat($toaddr);
2038                  }
2039              }
2040          } else {
2041              if (count($this->to) > 0) {
2042                  if ($this->Mailer != 'mail') {
2043                      $result .= $this->addrAppend('To', $this->to);
2044                  }
2045              } elseif (count($this->cc) == 0) {
2046                  $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2047              }
2048          }
2049  
2050          $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2051  
2052          // sendmail and mail() extract Cc from the header before sending
2053          if (count($this->cc) > 0) {
2054              $result .= $this->addrAppend('Cc', $this->cc);
2055          }
2056  
2057          // sendmail and mail() extract Bcc from the header before sending
2058          if ((
2059                  $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2060              )
2061              and count($this->bcc) > 0
2062          ) {
2063              $result .= $this->addrAppend('Bcc', $this->bcc);
2064          }
2065  
2066          if (count($this->ReplyTo) > 0) {
2067              $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2068          }
2069  
2070          // mail() sets the subject itself
2071          if ($this->Mailer != 'mail') {
2072              $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2073          }
2074  
2075          // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
2076          // https://tools.ietf.org/html/rfc5322#section-3.6.4
2077          if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2078              $this->lastMessageID = $this->MessageID;
2079          } else {
2080              $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2081          }
2082          $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2083          if (!is_null($this->Priority)) {
2084              $result .= $this->headerLine('X-Priority', $this->Priority);
2085          }
2086          if ($this->XMailer == '') {
2087              $result .= $this->headerLine(
2088                  'X-Mailer',
2089                  'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2090              );
2091          } else {
2092              $myXmailer = trim($this->XMailer);
2093              if ($myXmailer) {
2094                  $result .= $this->headerLine('X-Mailer', $myXmailer);
2095              }
2096          }
2097  
2098          if ($this->ConfirmReadingTo != '') {
2099              $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2100          }
2101  
2102          // Add custom headers
2103          foreach ($this->CustomHeader as $header) {
2104              $result .= $this->headerLine(
2105                  trim($header[0]),
2106                  $this->encodeHeader(trim($header[1]))
2107              );
2108          }
2109          if (!$this->sign_key_file) {
2110              $result .= $this->headerLine('MIME-Version', '1.0');
2111              $result .= $this->getMailMIME();
2112          }
2113  
2114          return $result;
2115      }
2116  
2117      /**
2118       * Get the message MIME type headers.
2119       * @access public
2120       * @return string
2121       */
2122      public function getMailMIME()
2123      {
2124          $result = '';
2125          $ismultipart = true;
2126          switch ($this->message_type) {
2127              case 'inline':
2128                  $result .= $this->headerLine('Content-Type', 'multipart/related;');
2129                  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2130                  break;
2131              case 'attach':
2132              case 'inline_attach':
2133              case 'alt_attach':
2134              case 'alt_inline_attach':
2135                  $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2136                  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2137                  break;
2138              case 'alt':
2139              case 'alt_inline':
2140                  $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2141                  $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2142                  break;
2143              default:
2144                  // Catches case 'plain': and case '':
2145                  $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2146                  $ismultipart = false;
2147                  break;
2148          }
2149          // RFC1341 part 5 says 7bit is assumed if not specified
2150          if ($this->Encoding != '7bit') {
2151              // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2152              if ($ismultipart) {
2153                  if ($this->Encoding == '8bit') {
2154                      $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2155                  }
2156                  // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2157              } else {
2158                  $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2159              }
2160          }
2161  
2162          if ($this->Mailer != 'mail') {
2163              $result .= $this->LE;
2164          }
2165  
2166          return $result;
2167      }
2168  
2169      /**
2170       * Returns the whole MIME message.
2171       * Includes complete headers and body.
2172       * Only valid post preSend().
2173       * @see PHPMailer::preSend()
2174       * @access public
2175       * @return string
2176       */
2177      public function getSentMIMEMessage()
2178      {
2179          return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2180      }
2181  
2182      /**
2183       * Create unique ID
2184       * @return string
2185       */
2186      protected function generateId() {
2187          return md5(uniqid(time()));
2188      }
2189  
2190      /**
2191       * Assemble the message body.
2192       * Returns an empty string on failure.
2193       * @access public
2194       * @throws phpmailerException
2195       * @return string The assembled message body
2196       */
2197      public function createBody()
2198      {
2199          $body = '';
2200          //Create unique IDs and preset boundaries
2201          $this->uniqueid = $this->generateId();
2202          $this->boundary[1] = 'b1_' . $this->uniqueid;
2203          $this->boundary[2] = 'b2_' . $this->uniqueid;
2204          $this->boundary[3] = 'b3_' . $this->uniqueid;
2205  
2206          if ($this->sign_key_file) {
2207              $body .= $this->getMailMIME() . $this->LE;
2208          }
2209  
2210          $this->setWordWrap();
2211  
2212          $bodyEncoding = $this->Encoding;
2213          $bodyCharSet = $this->CharSet;
2214          //Can we do a 7-bit downgrade?
2215          if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2216              $bodyEncoding = '7bit';
2217              //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2218              $bodyCharSet = 'us-ascii';
2219          }
2220          //If lines are too long, and we're not already using an encoding that will shorten them,
2221          //change to quoted-printable transfer encoding for the body part only
2222          if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2223              $bodyEncoding = 'quoted-printable';
2224          }
2225  
2226          $altBodyEncoding = $this->Encoding;
2227          $altBodyCharSet = $this->CharSet;
2228          //Can we do a 7-bit downgrade?
2229          if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2230              $altBodyEncoding = '7bit';
2231              //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
2232              $altBodyCharSet = 'us-ascii';
2233          }
2234          //If lines are too long, and we're not already using an encoding that will shorten them,
2235          //change to quoted-printable transfer encoding for the alt body part only
2236          if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2237              $altBodyEncoding = 'quoted-printable';
2238          }
2239          //Use this as a preamble in all multipart message types
2240          $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2241          switch ($this->message_type) {
2242              case 'inline':
2243                  $body .= $mimepre;
2244                  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2245                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2246                  $body .= $this->LE . $this->LE;
2247                  $body .= $this->attachAll('inline', $this->boundary[1]);
2248                  break;
2249              case 'attach':
2250                  $body .= $mimepre;
2251                  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2252                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2253                  $body .= $this->LE . $this->LE;
2254                  $body .= $this->attachAll('attachment', $this->boundary[1]);
2255                  break;
2256              case 'inline_attach':
2257                  $body .= $mimepre;
2258                  $body .= $this->textLine('--' . $this->boundary[1]);
2259                  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2260                  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2261                  $body .= $this->LE;
2262                  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2263                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2264                  $body .= $this->LE . $this->LE;
2265                  $body .= $this->attachAll('inline', $this->boundary[2]);
2266                  $body .= $this->LE;
2267                  $body .= $this->attachAll('attachment', $this->boundary[1]);
2268                  break;
2269              case 'alt':
2270                  $body .= $mimepre;
2271                  $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2272                  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2273                  $body .= $this->LE . $this->LE;
2274                  $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2275                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2276                  $body .= $this->LE . $this->LE;
2277                  if (!empty($this->Ical)) {
2278                      $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2279                      $body .= $this->encodeString($this->Ical, $this->Encoding);
2280                      $body .= $this->LE . $this->LE;
2281                  }
2282                  $body .= $this->endBoundary($this->boundary[1]);
2283                  break;
2284              case 'alt_inline':
2285                  $body .= $mimepre;
2286                  $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2287                  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2288                  $body .= $this->LE . $this->LE;
2289                  $body .= $this->textLine('--' . $this->boundary[1]);
2290                  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2291                  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2292                  $body .= $this->LE;
2293                  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2294                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2295                  $body .= $this->LE . $this->LE;
2296                  $body .= $this->attachAll('inline', $this->boundary[2]);
2297                  $body .= $this->LE;
2298                  $body .= $this->endBoundary($this->boundary[1]);
2299                  break;
2300              case 'alt_attach':
2301                  $body .= $mimepre;
2302                  $body .= $this->textLine('--' . $this->boundary[1]);
2303                  $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2304                  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2305                  $body .= $this->LE;
2306                  $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2307                  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2308                  $body .= $this->LE . $this->LE;
2309                  $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2310                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2311                  $body .= $this->LE . $this->LE;
2312                  $body .= $this->endBoundary($this->boundary[2]);
2313                  $body .= $this->LE;
2314                  $body .= $this->attachAll('attachment', $this->boundary[1]);
2315                  break;
2316              case 'alt_inline_attach':
2317                  $body .= $mimepre;
2318                  $body .= $this->textLine('--' . $this->boundary[1]);
2319                  $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2320                  $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2321                  $body .= $this->LE;
2322                  $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2323                  $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2324                  $body .= $this->LE . $this->LE;
2325                  $body .= $this->textLine('--' . $this->boundary[2]);
2326                  $body .= $this->headerLine('Content-Type', 'multipart/related;');
2327                  $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2328                  $body .= $this->LE;
2329                  $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2330                  $body .= $this->encodeString($this->Body, $bodyEncoding);
2331                  $body .= $this->LE . $this->LE;
2332                  $body .= $this->attachAll('inline', $this->boundary[3]);
2333                  $body .= $this->LE;
2334                  $body .= $this->endBoundary($this->boundary[2]);
2335                  $body .= $this->LE;
2336                  $body .= $this->attachAll('attachment', $this->boundary[1]);
2337                  break;
2338              default:
2339                  // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
2340                  //Reset the `Encoding` property in case we changed it for line length reasons
2341                  $this->Encoding = $bodyEncoding;
2342                  $body .= $this->encodeString($this->Body, $this->Encoding);
2343                  break;
2344          }
2345  
2346          if ($this->isError()) {
2347              $body = '';
2348          } elseif ($this->sign_key_file) {
2349              try {
2350                  if (!defined('PKCS7_TEXT')) {
2351                      throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2352                  }
2353                  // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2354                  $file = tempnam(sys_get_temp_dir(), 'mail');
2355                  if (false === file_put_contents($file, $body)) {
2356                      throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2357                  }
2358                  $signed = tempnam(sys_get_temp_dir(), 'signed');
2359                  //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2360                  if (empty($this->sign_extracerts_file)) {
2361                      $sign = @openssl_pkcs7_sign(
2362                          $file,
2363                          $signed,
2364                          'file://' . realpath($this->sign_cert_file),
2365                          array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2366                          null
2367                      );
2368                  } else {
2369                      $sign = @openssl_pkcs7_sign(
2370                          $file,
2371                          $signed,
2372                          'file://' . realpath($this->sign_cert_file),
2373                          array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2374                          null,
2375                          PKCS7_DETACHED,
2376                          $this->sign_extracerts_file
2377                      );
2378                  }
2379                  if ($sign) {
2380                      @unlink($file);
2381                      $body = file_get_contents($signed);
2382                      @unlink($signed);
2383                      //The message returned by openssl contains both headers and body, so need to split them up
2384                      $parts = explode("\n\n", $body, 2);
2385                      $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2386                      $body = $parts[1];
2387                  } else {
2388                      @unlink($file);
2389                      @unlink($signed);
2390                      throw new phpmailerException($this->lang('signing') . openssl_error_string());
2391                  }
2392              } catch (phpmailerException $exc) {
2393                  $body = '';
2394                  if ($this->exceptions) {
2395                      throw $exc;
2396                  }
2397              }
2398          }
2399          return $body;
2400      }
2401  
2402      /**
2403       * Return the start of a message boundary.
2404       * @access protected
2405       * @param string $boundary
2406       * @param string $charSet
2407       * @param string $contentType
2408       * @param string $encoding
2409       * @return string
2410       */
2411      protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2412      {
2413          $result = '';
2414          if ($charSet == '') {
2415              $charSet = $this->CharSet;
2416          }
2417          if ($contentType == '') {
2418              $contentType = $this->ContentType;
2419          }
2420          if ($encoding == '') {
2421              $encoding = $this->Encoding;
2422          }
2423          $result .= $this->textLine('--' . $boundary);
2424          $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2425          $result .= $this->LE;
2426          // RFC1341 part 5 says 7bit is assumed if not specified
2427          if ($encoding != '7bit') {
2428              $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2429          }
2430          $result .= $this->LE;
2431  
2432          return $result;
2433      }
2434  
2435      /**
2436       * Return the end of a message boundary.
2437       * @access protected
2438       * @param string $boundary
2439       * @return string
2440       */
2441      protected function endBoundary($boundary)
2442      {
2443          return $this->LE . '--' . $boundary . '--' . $this->LE;
2444      }
2445  
2446      /**
2447       * Set the message type.
2448       * PHPMailer only supports some preset message types, not arbitrary MIME structures.
2449       * @access protected
2450       * @return void
2451       */
2452      protected function setMessageType()
2453      {
2454          $type = array();
2455          if ($this->alternativeExists()) {
2456              $type[] = 'alt';
2457          }
2458          if ($this->inlineImageExists()) {
2459              $type[] = 'inline';
2460          }
2461          if ($this->attachmentExists()) {
2462              $type[] = 'attach';
2463          }
2464          $this->message_type = implode('_', $type);
2465          if ($this->message_type == '') {
2466              //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
2467              $this->message_type = 'plain';
2468          }
2469      }
2470  
2471      /**
2472       * Format a header line.
2473       * @access public
2474       * @param string $name
2475       * @param string $value
2476       * @return string
2477       */
2478      public function headerLine($name, $value)
2479      {
2480          return $name . ': ' . $value . $this->LE;
2481      }
2482  
2483      /**
2484       * Return a formatted mail line.
2485       * @access public
2486       * @param string $value
2487       * @return string
2488       */
2489      public function textLine($value)
2490      {
2491          return $value . $this->LE;
2492      }
2493  
2494      /**
2495       * Add an attachment from a path on the filesystem.
2496       * Never use a user-supplied path to a file!
2497       * Returns false if the file could not be found or read.
2498       * @param string $path Path to the attachment.
2499       * @param string $name Overrides the attachment name.
2500       * @param string $encoding File encoding (see $Encoding).
2501       * @param string $type File extension (MIME) type.
2502       * @param string $disposition Disposition to use
2503       * @throws phpmailerException
2504       * @return boolean
2505       */
2506      public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2507      {
2508          try {
2509              if (!@is_file($path)) {
2510                  throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2511              }
2512  
2513              // If a MIME type is not specified, try to work it out from the file name
2514              if ($type == '') {
2515                  $type = self::filenameToType($path);
2516              }
2517  
2518              $filename = basename($path);
2519              if ($name == '') {
2520                  $name = $filename;
2521              }
2522  
2523              $this->attachment[] = array(
2524                  0 => $path,
2525                  1 => $filename,
2526                  2 => $name,
2527                  3 => $encoding,
2528                  4 => $type,
2529                  5 => false, // isStringAttachment
2530                  6 => $disposition,
2531                  7 => 0
2532              );
2533  
2534          } catch (phpmailerException $exc) {
2535              $this->setError($exc->getMessage());
2536              $this->edebug($exc->getMessage());
2537              if ($this->exceptions) {
2538                  throw $exc;
2539              }
2540              return false;
2541          }
2542          return true;
2543      }
2544  
2545      /**
2546       * Return the array of attachments.
2547       * @return array
2548       */
2549      public function getAttachments()
2550      {
2551          return $this->attachment;
2552      }
2553  
2554      /**
2555       * Attach all file, string, and binary attachments to the message.
2556       * Returns an empty string on failure.
2557       * @access protected
2558       * @param string $disposition_type
2559       * @param string $boundary
2560       * @return string
2561       */
2562      protected function attachAll($disposition_type, $boundary)
2563      {
2564          // Return text of body
2565          $mime = array();
2566          $cidUniq = array();
2567          $incl = array();
2568  
2569          // Add all attachments
2570          foreach ($this->attachment as $attachment) {
2571              // Check if it is a valid disposition_filter
2572              if ($attachment[6] == $disposition_type) {
2573                  // Check for string attachment
2574                  $string = '';
2575                  $path = '';
2576                  $bString = $attachment[5];
2577                  if ($bString) {
2578                      $string = $attachment[0];
2579                  } else {
2580                      $path = $attachment[0];
2581                  }
2582  
2583                  $inclhash = md5(serialize($attachment));
2584                  if (in_array($inclhash, $incl)) {
2585                      continue;
2586                  }
2587                  $incl[] = $inclhash;
2588                  $name = $attachment[2];
2589                  $encoding = $attachment[3];
2590                  $type = $attachment[4];
2591                  $disposition = $attachment[6];
2592                  $cid = $attachment[7];
2593                  if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2594                      continue;
2595                  }
2596                  $cidUniq[$cid] = true;
2597  
2598                  $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2599                  //Only include a filename property if we have one
2600                  if (!empty($name)) {
2601                      $mime[] = sprintf(
2602                          'Content-Type: %s; name="%s"%s',
2603                          $type,
2604                          $this->encodeHeader($this->secureHeader($name)),
2605                          $this->LE
2606                      );
2607                  } else {
2608                      $mime[] = sprintf(
2609                          'Content-Type: %s%s',
2610                          $type,
2611                          $this->LE
2612                      );
2613                  }
2614                  // RFC1341 part 5 says 7bit is assumed if not specified
2615                  if ($encoding != '7bit') {
2616                      $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2617                  }
2618  
2619                  if ($disposition == 'inline') {
2620                      $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2621                  }
2622  
2623                  // If a filename contains any of these chars, it should be quoted,
2624                  // but not otherwise: RFC2183 & RFC2045 5.1
2625                  // Fixes a warning in IETF's msglint MIME checker
2626                  // Allow for bypassing the Content-Disposition header totally
2627                  if (!(empty($disposition))) {
2628                      $encoded_name = $this->encodeHeader($this->secureHeader($name));
2629                      if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2630                          $mime[] = sprintf(
2631                              'Content-Disposition: %s; filename="%s"%s',
2632                              $disposition,
2633                              $encoded_name,
2634                              $this->LE . $this->LE
2635                          );
2636                      } else {
2637                          if (!empty($encoded_name)) {
2638                              $mime[] = sprintf(
2639                                  'Content-Disposition: %s; filename=%s%s',
2640                                  $disposition,
2641                                  $encoded_name,
2642                                  $this->LE . $this->LE
2643                              );
2644                          } else {
2645                              $mime[] = sprintf(
2646                                  'Content-Disposition: %s%s',
2647                                  $disposition,
2648                                  $this->LE . $this->LE
2649                              );
2650                          }
2651                      }
2652                  } else {
2653                      $mime[] = $this->LE;
2654                  }
2655  
2656                  // Encode as string attachment
2657                  if ($bString) {
2658                      $mime[] = $this->encodeString($string, $encoding);
2659                      if ($this->isError()) {
2660                          return '';
2661                      }
2662                      $mime[] = $this->LE . $this->LE;
2663                  } else {
2664                      $mime[] = $this->encodeFile($path, $encoding);
2665                      if ($this->isError()) {
2666                          return '';
2667                      }
2668                      $mime[] = $this->LE . $this->LE;
2669                  }
2670              }
2671          }
2672  
2673          $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2674  
2675          return implode('', $mime);
2676      }
2677  
2678      /**
2679       * Encode a file attachment in requested format.
2680       * Returns an empty string on failure.
2681       * @param string $path The full path to the file
2682       * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2683       * @throws phpmailerException
2684       * @access protected
2685       * @return string
2686       */
2687      protected function encodeFile($path, $encoding = 'base64')
2688      {
2689          try {
2690              if (!is_readable($path)) {
2691                  throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2692              }
2693              $magic_quotes = get_magic_quotes_runtime();
2694              if ($magic_quotes) {
2695                  if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2696                      set_magic_quotes_runtime(false);
2697                  } else {
2698                      //Doesn't exist in PHP 5.4, but we don't need to check because
2699                      //get_magic_quotes_runtime always returns false in 5.4+
2700                      //so it will never get here
2701                      ini_set('magic_quotes_runtime', false);
2702                  }
2703              }
2704              $file_buffer = file_get_contents($path);
2705              $file_buffer = $this->encodeString($file_buffer, $encoding);
2706              if ($magic_quotes) {
2707                  if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2708                      set_magic_quotes_runtime($magic_quotes);
2709                  } else {
2710                      ini_set('magic_quotes_runtime', $magic_quotes);
2711                  }
2712              }
2713              return $file_buffer;
2714          } catch (Exception $exc) {
2715              $this->setError($exc->getMessage());
2716              return '';
2717          }
2718      }
2719  
2720      /**
2721       * Encode a string in requested format.
2722       * Returns an empty string on failure.
2723       * @param string $str The text to encode
2724       * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2725       * @access public
2726       * @return string
2727       */
2728      public function encodeString($str, $encoding = 'base64')
2729      {
2730          $encoded = '';
2731          switch (strtolower($encoding)) {
2732              case 'base64':
2733                  $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2734                  break;
2735              case '7bit':
2736              case '8bit':
2737                  $encoded = $this->fixEOL($str);
2738                  // Make sure it ends with a line break
2739                  if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2740                      $encoded .= $this->LE;
2741                  }
2742                  break;
2743              case 'binary':
2744                  $encoded = $str;
2745                  break;
2746              case 'quoted-printable':
2747                  $encoded = $this->encodeQP($str);
2748                  break;
2749              default:
2750                  $this->setError($this->lang('encoding') . $encoding);
2751                  break;
2752          }
2753          return $encoded;
2754      }
2755  
2756      /**
2757       * Encode a header string optimally.
2758       * Picks shortest of Q, B, quoted-printable or none.
2759       * @access public
2760       * @param string $str
2761       * @param string $position
2762       * @return string
2763       */
2764      public function encodeHeader($str, $position = 'text')
2765      {
2766          $matchcount = 0;
2767          switch (strtolower($position)) {
2768              case 'phrase':
2769                  if (!preg_match('/[\200-\377]/', $str)) {
2770                      // Can't use addslashes as we don't know the value of magic_quotes_sybase
2771                      $encoded = addcslashes($str, "\0..\37\177\\\"");
2772                      if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2773                          return ($encoded);
2774                      } else {
2775                          return ("\"$encoded\"");
2776                      }
2777                  }
2778                  $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2779                  break;
2780              /** @noinspection PhpMissingBreakStatementInspection */
2781              case 'comment':
2782                  $matchcount = preg_match_all('/[()"]/', $str, $matches);
2783                  // Intentional fall-through
2784              case 'text':
2785              default:
2786                  $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2787                  break;
2788          }
2789  
2790          //There are no chars that need encoding
2791          if ($matchcount == 0) {
2792              return ($str);
2793          }
2794  
2795          $maxlen = 75 - 7 - strlen($this->CharSet);
2796          // Try to select the encoding which should produce the shortest output
2797          if ($matchcount > strlen($str) / 3) {
2798              // More than a third of the content will need encoding, so B encoding will be most efficient
2799              $encoding = 'B';
2800              if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2801                  // Use a custom function which correctly encodes and wraps long
2802                  // multibyte strings without breaking lines within a character
2803                  $encoded = $this->base64EncodeWrapMB($str, "\n");
2804              } else {
2805                  $encoded = base64_encode($str);
2806                  $maxlen -= $maxlen % 4;
2807                  $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2808              }
2809          } else {
2810              $encoding = 'Q';
2811              $encoded = $this->encodeQ($str, $position);
2812              $encoded = $this->wrapText($encoded, $maxlen, true);
2813              $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2814          }
2815  
2816          $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2817          $encoded = trim(str_replace("\n", $this->LE, $encoded));
2818  
2819          return $encoded;
2820      }
2821  
2822      /**
2823       * Check if a string contains multi-byte characters.
2824       * @access public
2825       * @param string $str multi-byte text to wrap encode
2826       * @return boolean
2827       */
2828      public function hasMultiBytes($str)
2829      {
2830          if (function_exists('mb_strlen')) {
2831              return (strlen($str) > mb_strlen($str, $this->CharSet));
2832          } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2833              return false;
2834          }
2835      }
2836  
2837      /**
2838       * Does a string contain any 8-bit chars (in any charset)?
2839       * @param string $text
2840       * @return boolean
2841       */
2842      public function has8bitChars($text)
2843      {
2844          return (boolean)preg_match('/[\x80-\xFF]/', $text);
2845      }
2846  
2847      /**
2848       * Encode and wrap long multibyte strings for mail headers
2849       * without breaking lines within a character.
2850       * Adapted from a function by paravoid
2851       * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2852       * @access public
2853       * @param string $str multi-byte text to wrap encode
2854       * @param string $linebreak string to use as linefeed/end-of-line
2855       * @return string
2856       */
2857      public function base64EncodeWrapMB($str, $linebreak = null)
2858      {
2859          $start = '=?' . $this->CharSet . '?B?';
2860          $end = '?=';
2861          $encoded = '';
2862          if ($linebreak === null) {
2863              $linebreak = $this->LE;
2864          }
2865  
2866          $mb_length = mb_strlen($str, $this->CharSet);
2867          // Each line must have length <= 75, including $start and $end
2868          $length = 75 - strlen($start) - strlen($end);
2869          // Average multi-byte ratio
2870          $ratio = $mb_length / strlen($str);
2871          // Base64 has a 4:3 ratio
2872          $avgLength = floor($length * $ratio * .75);
2873  
2874          for ($i = 0; $i < $mb_length; $i += $offset) {
2875              $lookBack = 0;
2876              do {
2877                  $offset = $avgLength - $lookBack;
2878                  $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2879                  $chunk = base64_encode($chunk);
2880                  $lookBack++;
2881              } while (strlen($chunk) > $length);
2882              $encoded .= $chunk . $linebreak;
2883          }
2884  
2885          // Chomp the last linefeed
2886          $encoded = substr($encoded, 0, -strlen($linebreak));
2887          return $encoded;
2888      }
2889  
2890      /**
2891       * Encode a string in quoted-printable format.
2892       * According to RFC2045 section 6.7.
2893       * @access public
2894       * @param string $string The text to encode
2895       * @param integer $line_max Number of chars allowed on a line before wrapping
2896       * @return string
2897       * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
2898       */
2899      public function encodeQP($string, $line_max = 76)
2900      {
2901          // Use native function if it's available (>= PHP5.3)
2902          if (function_exists('quoted_printable_encode')) {
2903              return quoted_printable_encode($string);
2904          }
2905          // Fall back to a pure PHP implementation
2906          $string = str_replace(
2907              array('%20', '%0D%0A.', '%0D%0A', '%'),
2908              array(' ', "\r\n=2E", "\r\n", '='),
2909              rawurlencode($string)
2910          );
2911          return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2912      }
2913  
2914      /**
2915       * Backward compatibility wrapper for an old QP encoding function that was removed.
2916       * @see PHPMailer::encodeQP()
2917       * @access public
2918       * @param string $string
2919       * @param integer $line_max
2920       * @param boolean $space_conv
2921       * @return string
2922       * @deprecated Use encodeQP instead.
2923       */
2924      public function encodeQPphp(
2925          $string,
2926          $line_max = 76,
2927          /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
2928      ) {
2929          return $this->encodeQP($string, $line_max);
2930      }
2931  
2932      /**
2933       * Encode a string using Q encoding.
2934       * @link http://tools.ietf.org/html/rfc2047
2935       * @param string $str the text to encode
2936       * @param string $position Where the text is going to be used, see the RFC for what that means
2937       * @access public
2938       * @return string
2939       */
2940      public function encodeQ($str, $position = 'text')
2941      {
2942          // There should not be any EOL in the string
2943          $pattern = '';
2944          $encoded = str_replace(array("\r", "\n"), '', $str);
2945          switch (strtolower($position)) {
2946              case 'phrase':
2947                  // RFC 2047 section 5.3
2948                  $pattern = '^A-Za-z0-9!*+\/ -';
2949                  break;
2950              /** @noinspection PhpMissingBreakStatementInspection */
2951              case 'comment':
2952                  // RFC 2047 section 5.2
2953                  $pattern = '\(\)"';
2954                  // intentional fall-through
2955                  // for this reason we build the $pattern without including delimiters and []
2956              case 'text':
2957              default:
2958                  // RFC 2047 section 5.1
2959                  // Replace every high ascii, control, =, ? and _ characters
2960                  $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2961                  break;
2962          }
2963          $matches = array();
2964          if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2965              // If the string contains an '=', make sure it's the first thing we replace
2966              // so as to avoid double-encoding
2967              $eqkey = array_search('=', $matches[0]);
2968              if (false !== $eqkey) {
2969                  unset($matches[0][$eqkey]);
2970                  array_unshift($matches[0], '=');
2971              }
2972              foreach (array_unique($matches[0]) as $char) {
2973                  $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2974              }
2975          }
2976          // Replace every spaces to _ (more readable than =20)
2977          return str_replace(' ', '_', $encoded);
2978      }
2979  
2980      /**
2981       * Add a string or binary attachment (non-filesystem).
2982       * This method can be used to attach ascii or binary data,
2983       * such as a BLOB record from a database.
2984       * @param string $string String attachment data.
2985       * @param string $filename Name of the attachment.
2986       * @param string $encoding File encoding (see $Encoding).
2987       * @param string $type File extension (MIME) type.
2988       * @param string $disposition Disposition to use
2989       * @return void
2990       */
2991      public function addStringAttachment(
2992          $string,
2993          $filename,
2994          $encoding = 'base64',
2995          $type = '',
2996          $disposition = 'attachment'
2997      ) {
2998          // If a MIME type is not specified, try to work it out from the file name
2999          if ($type == '') {
3000              $type = self::filenameToType($filename);
3001          }
3002          // Append to $attachment array
3003          $this->attachment[] = array(
3004              0 => $string,
3005              1 => $filename,
3006              2 => basename($filename),
3007              3 => $encoding,
3008              4 => $type,
3009              5 => true, // isStringAttachment
3010              6 => $disposition,
3011              7 => 0
3012          );
3013      }
3014  
3015      /**
3016       * Add an embedded (inline) attachment from a file.
3017       * This can include images, sounds, and just about any other document type.
3018       * These differ from 'regular' attachments in that they are intended to be
3019       * displayed inline with the message, not just attached for download.
3020       * This is used in HTML messages that embed the images
3021       * the HTML refers to using the $cid value.
3022       * Never use a user-supplied path to a file!
3023       * @param string $path Path to the attachment.
3024       * @param string $cid Content ID of the attachment; Use this to reference
3025       *        the content when using an embedded image in HTML.
3026       * @param string $name Overrides the attachment name.
3027       * @param string $encoding File encoding (see $Encoding).
3028       * @param string $type File MIME type.
3029       * @param string $disposition Disposition to use
3030       * @return boolean True on successfully adding an attachment
3031       */
3032      public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3033      {
3034          if (!@is_file($path)) {
3035              $this->setError($this->lang('file_access') . $path);
3036              return false;
3037          }
3038  
3039          // If a MIME type is not specified, try to work it out from the file name
3040          if ($type == '') {
3041              $type = self::filenameToType($path);
3042          }
3043  
3044          $filename = basename($path);
3045          if ($name == '') {
3046              $name = $filename;
3047          }
3048  
3049          // Append to $attachment array
3050          $this->attachment[] = array(
3051              0 => $path,
3052              1 => $filename,
3053              2 => $name,
3054              3 => $encoding,
3055              4 => $type,
3056              5 => false, // isStringAttachment
3057              6 => $disposition,
3058              7 => $cid
3059          );
3060          return true;
3061      }
3062  
3063      /**
3064       * Add an embedded stringified attachment.
3065       * This can include images, sounds, and just about any other document type.
3066       * Be sure to set the $type to an image type for images:
3067       * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
3068       * @param string $string The attachment binary data.
3069       * @param string $cid Content ID of the attachment; Use this to reference
3070       *        the content when using an embedded image in HTML.
3071       * @param string $name
3072       * @param string $encoding File encoding (see $Encoding).
3073       * @param string $type MIME type.
3074       * @param string $disposition Disposition to use
3075       * @return boolean True on successfully adding an attachment
3076       */
3077      public function addStringEmbeddedImage(
3078          $string,
3079          $cid,
3080          $name = '',
3081          $encoding = 'base64',
3082          $type = '',
3083          $disposition = 'inline'
3084      ) {
3085          // If a MIME type is not specified, try to work it out from the name
3086          if ($type == '' and !empty($name)) {
3087              $type = self::filenameToType($name);
3088          }
3089  
3090          // Append to $attachment array
3091          $this->attachment[] = array(
3092              0 => $string,
3093              1 => $name,
3094              2 => $name,
3095              3 => $encoding,
3096              4 => $type,
3097              5 => true, // isStringAttachment
3098              6 => $disposition,
3099              7 => $cid
3100          );
3101          return true;
3102      }
3103  
3104      /**
3105       * Check if an inline attachment is present.
3106       * @access public
3107       * @return boolean
3108       */
3109      public function inlineImageExists()
3110      {
3111          foreach ($this->attachment as $attachment) {
3112              if ($attachment[6] == 'inline') {
3113                  return true;
3114              }
3115          }
3116          return false;
3117      }
3118  
3119      /**
3120       * Check if an attachment (non-inline) is present.
3121       * @return boolean
3122       */
3123      public function attachmentExists()
3124      {
3125          foreach ($this->attachment as $attachment) {
3126              if ($attachment[6] == 'attachment') {
3127                  return true;
3128              }
3129          }
3130          return false;
3131      }
3132  
3133      /**
3134       * Check if this message has an alternative body set.
3135       * @return boolean
3136       */
3137      public function alternativeExists()
3138      {
3139          return !empty($this->AltBody);
3140      }
3141  
3142      /**
3143       * Clear queued addresses of given kind.
3144       * @access protected
3145       * @param string $kind 'to', 'cc', or 'bcc'
3146       * @return void
3147       */
3148      public function clearQueuedAddresses($kind)
3149      {
3150          $RecipientsQueue = $this->RecipientsQueue;
3151          foreach ($RecipientsQueue as $address => $params) {
3152              if ($params[0] == $kind) {
3153                  unset($this->RecipientsQueue[$address]);
3154              }
3155          }
3156      }
3157  
3158      /**
3159       * Clear all To recipients.
3160       * @return void
3161       */
3162      public function clearAddresses()
3163      {
3164          foreach ($this->to as $to) {
3165              unset($this->all_recipients[strtolower($to[0])]);
3166          }
3167          $this->to = array();
3168          $this->clearQueuedAddresses('to');
3169      }
3170  
3171      /**
3172       * Clear all CC recipients.
3173       * @return void
3174       */
3175      public function clearCCs()
3176      {
3177          foreach ($this->cc as $cc) {
3178              unset($this->all_recipients[strtolower($cc[0])]);
3179          }
3180          $this->cc = array();
3181          $this->clearQueuedAddresses('cc');
3182      }
3183  
3184      /**
3185       * Clear all BCC recipients.
3186       * @return void
3187       */
3188      public function clearBCCs()
3189      {
3190          foreach ($this->bcc as $bcc) {
3191              unset($this->all_recipients[strtolower($bcc[0])]);
3192          }
3193          $this->bcc = array();
3194          $this->clearQueuedAddresses('bcc');
3195      }
3196  
3197      /**
3198       * Clear all ReplyTo recipients.
3199       * @return void
3200       */
3201      public function clearReplyTos()
3202      {
3203          $this->ReplyTo = array();
3204          $this->ReplyToQueue = array();
3205      }
3206  
3207      /**
3208       * Clear all recipient types.
3209       * @return void
3210       */
3211      public function clearAllRecipients()
3212      {
3213          $this->to = array();
3214          $this->cc = array();
3215          $this->bcc = array();
3216          $this->all_recipients = array();
3217          $this->RecipientsQueue = array();
3218      }
3219  
3220      /**
3221       * Clear all filesystem, string, and binary attachments.
3222       * @return void
3223       */
3224      public function clearAttachments()
3225      {
3226          $this->attachment = array();
3227      }
3228  
3229      /**
3230       * Clear all custom headers.
3231       * @return void
3232       */
3233      public function clearCustomHeaders()
3234      {
3235          $this->CustomHeader = array();
3236      }
3237  
3238      /**
3239       * Add an error message to the error container.
3240       * @access protected
3241       * @param string $msg
3242       * @return void
3243       */
3244      protected function setError($msg)
3245      {
3246          $this->error_count++;
3247          if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3248              $lasterror = $this->smtp->getError();
3249              if (!empty($lasterror['error'])) {
3250                  $msg .= $this->lang('smtp_error') . $lasterror['error'];
3251                  if (!empty($lasterror['detail'])) {
3252                      $msg .= ' Detail: '. $lasterror['detail'];
3253                  }
3254                  if (!empty($lasterror['smtp_code'])) {
3255                      $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3256                  }
3257                  if (!empty($lasterror['smtp_code_ex'])) {
3258                      $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3259                  }
3260              }
3261          }
3262          $this->ErrorInfo = $msg;
3263      }
3264  
3265      /**
3266       * Return an RFC 822 formatted date.
3267       * @access public
3268       * @return string
3269       * @static
3270       */
3271      public static function rfcDate()
3272      {
3273          // Set the time zone to whatever the default is to avoid 500 errors
3274          // Will default to UTC if it's not set properly in php.ini
3275          date_default_timezone_set(@date_default_timezone_get());
3276          return date('D, j M Y H:i:s O');
3277      }
3278  
3279      /**
3280       * Get the server hostname.
3281       * Returns 'localhost.localdomain' if unknown.
3282       * @access protected
3283       * @return string
3284       */
3285      protected function serverHostname()
3286      {
3287          $result = 'localhost.localdomain';
3288          if (!empty($this->Hostname)) {
3289              $result = $this->Hostname;
3290          } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3291              $result = $_SERVER['SERVER_NAME'];
3292          } elseif (function_exists('gethostname') && gethostname() !== false) {
3293              $result = gethostname();
3294          } elseif (php_uname('n') !== false) {
3295              $result = php_uname('n');
3296          }
3297          return $result;
3298      }
3299  
3300      /**
3301       * Get an error message in the current language.
3302       * @access protected
3303       * @param string $key
3304       * @return string
3305       */
3306      protected function lang($key)
3307      {
3308          if (count($this->language) < 1) {
3309              $this->setLanguage('en'); // set the default language
3310          }
3311  
3312          if (array_key_exists($key, $this->language)) {
3313              if ($key == 'smtp_connect_failed') {
3314                  //Include a link to troubleshooting docs on SMTP connection failure
3315                  //this is by far the biggest cause of support questions
3316                  //but it's usually not PHPMailer's fault.
3317                  return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3318              }
3319              return $this->language[$key];
3320          } else {
3321              //Return the key as a fallback
3322              return $key;
3323          }
3324      }
3325  
3326      /**
3327       * Check if an error occurred.
3328       * @access public
3329       * @return boolean True if an error did occur.
3330       */
3331      public function isError()
3332      {
3333          return ($this->error_count > 0);
3334      }
3335  
3336      /**
3337       * Ensure consistent line endings in a string.
3338       * Changes every end of line from CRLF, CR or LF to $this->LE.
3339       * @access public
3340       * @param string $str String to fixEOL
3341       * @return string
3342       */
3343      public function fixEOL($str)
3344      {
3345          // Normalise to \n
3346          $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3347          // Now convert LE as needed
3348          if ($this->LE !== "\n") {
3349              $nstr = str_replace("\n", $this->LE, $nstr);
3350          }
3351          return $nstr;
3352      }
3353  
3354      /**
3355       * Add a custom header.
3356       * $name value can be overloaded to contain
3357       * both header name and value (name:value)
3358       * @access public
3359       * @param string $name Custom header name
3360       * @param string $value Header value
3361       * @return void
3362       */
3363      public function addCustomHeader($name, $value = null)
3364      {
3365          if ($value === null) {
3366              // Value passed in as name:value
3367              $this->CustomHeader[] = explode(':', $name, 2);
3368          } else {
3369              $this->CustomHeader[] = array($name, $value);
3370          }
3371      }
3372  
3373      /**
3374       * Returns all custom headers.
3375       * @return array
3376       */
3377      public function getCustomHeaders()
3378      {
3379          return $this->CustomHeader;
3380      }
3381  
3382      /**
3383       * Create a message body from an HTML string.
3384       * Automatically inlines images and creates a plain-text version by converting the HTML,
3385       * overwriting any existing values in Body and AltBody.
3386       * Do not source $message content from user input!
3387       * $basedir is prepended when handling relative URLs, e.g. <img src="/images/a.png"> and must not be empty
3388       * will look for an image file in $basedir/images/a.png and convert it to inline.
3389       * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email)
3390       * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly.
3391       * @access public
3392       * @param string $message HTML message string
3393       * @param string $basedir Absolute path to a base directory to prepend to relative paths to images
3394       * @param boolean|callable $advanced Whether to use the internal HTML to text converter
3395       *    or your own custom converter @see PHPMailer::html2text()
3396       * @return string $message The transformed message Body
3397       */
3398      public function msgHTML($message, $basedir = '', $advanced = false)
3399      {
3400          preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3401          if (array_key_exists(2, $images)) {
3402              if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3403                  // Ensure $basedir has a trailing /
3404                  $basedir .= '/';
3405              }
3406              foreach ($images[2] as $imgindex => $url) {
3407                  // Convert data URIs into embedded images
3408                  if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3409                      $data = substr($url, strpos($url, ','));
3410                      if ($match[2]) {
3411                          $data = base64_decode($data);
3412                      } else {
3413                          $data = rawurldecode($data);
3414                      }
3415                      $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3416                      if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3417                          $message = str_replace(
3418                              $images[0][$imgindex],
3419                              $images[1][$imgindex] . '="cid:' . $cid . '"',
3420                              $message
3421                          );
3422                      }
3423                      continue;
3424                  }
3425                  if (
3426                      // Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
3427                      !empty($basedir)
3428                      // Ignore URLs containing parent dir traversal (..)
3429                      && (strpos($url, '..') === false)
3430                      // Do not change urls that are already inline images
3431                      && substr($url, 0, 4) !== 'cid:'
3432                      // Do not change absolute URLs, including anonymous protocol
3433                      && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
3434                  ) {
3435                      $filename = basename($url);
3436                      $directory = dirname($url);
3437                      if ($directory == '.') {
3438                          $directory = '';
3439                      }
3440                      $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3441                      if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3442                          $directory .= '/';
3443                      }
3444                      if ($this->addEmbeddedImage(
3445                          $basedir . $directory . $filename,
3446                          $cid,
3447                          $filename,
3448                          'base64',
3449                          self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3450                      )
3451                      ) {
3452                          $message = preg_replace(
3453                              '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3454                              $images[1][$imgindex] . '="cid:' . $cid . '"',
3455                              $message
3456                          );
3457                      }
3458                  }
3459              }
3460          }
3461          $this->isHTML(true);
3462          // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3463          $this->Body = $this->normalizeBreaks($message);
3464          $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3465          if (!$this->alternativeExists()) {
3466              $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3467                  self::CRLF . self::CRLF;
3468          }
3469          return $this->Body;
3470      }
3471  
3472      /**
3473       * Convert an HTML string into plain text.
3474       * This is used by msgHTML().
3475       * Note - older versions of this function used a bundled advanced converter
3476       * which was been removed for license reasons in #232.
3477       * Example usage:
3478       * <code>
3479       * // Use default conversion
3480       * $plain = $mail->html2text($html);
3481       * // Use your own custom converter
3482       * $plain = $mail->html2text($html, function($html) {
3483       *     $converter = new MyHtml2text($html);
3484       *     return $converter->get_text();
3485       * });
3486       * </code>
3487       * @param string $html The HTML text to convert
3488       * @param boolean|callable $advanced Any boolean value to use the internal converter,
3489       *   or provide your own callable for custom conversion.
3490       * @return string
3491       */
3492      public function html2text($html, $advanced = false)
3493      {
3494          if (is_callable($advanced)) {
3495              return call_user_func($advanced, $html);
3496          }
3497          return html_entity_decode(
3498              trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3499              ENT_QUOTES,
3500              $this->CharSet
3501          );
3502      }
3503  
3504      /**
3505       * Get the MIME type for a file extension.
3506       * @param string $ext File extension
3507       * @access public
3508       * @return string MIME type of file.
3509       * @static
3510       */
3511      public static function _mime_types($ext = '')
3512      {
3513          $mimes = array(
3514              'xl'    => 'application/excel',
3515              'js'    => 'application/javascript',
3516              'hqx'   => 'application/mac-binhex40',
3517              'cpt'   => 'application/mac-compactpro',
3518              'bin'   => 'application/macbinary',
3519              'doc'   => 'application/msword',
3520              'word'  => 'application/msword',
3521              'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3522              'xltx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3523              'potx'  => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3524              'ppsx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3525              'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3526              'sldx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3527              'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3528              'dotx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3529              'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
3530              'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3531              'class' => 'application/octet-stream',
3532              'dll'   => 'application/octet-stream',
3533              'dms'   => 'application/octet-stream',
3534              'exe'   => 'application/octet-stream',
3535              'lha'   => 'application/octet-stream',
3536              'lzh'   => 'application/octet-stream',
3537              'psd'   => 'application/octet-stream',
3538              'sea'   => 'application/octet-stream',
3539              'so'    => 'application/octet-stream',
3540              'oda'   => 'application/oda',
3541              'pdf'   => 'application/pdf',
3542              'ai'    => 'application/postscript',
3543              'eps'   => 'application/postscript',
3544              'ps'    => 'application/postscript',
3545              'smi'   => 'application/smil',
3546              'smil'  => 'application/smil',
3547              'mif'   => 'application/vnd.mif',
3548              'xls'   => 'application/vnd.ms-excel',
3549              'ppt'   => 'application/vnd.ms-powerpoint',
3550              'wbxml' => 'application/vnd.wap.wbxml',
3551              'wmlc'  => 'application/vnd.wap.wmlc',
3552              'dcr'   => 'application/x-director',
3553              'dir'   => 'application/x-director',
3554              'dxr'   => 'application/x-director',
3555              'dvi'   => 'application/x-dvi',
3556              'gtar'  => 'application/x-gtar',
3557              'php3'  => 'application/x-httpd-php',
3558              'php4'  => 'application/x-httpd-php',
3559              'php'   => 'application/x-httpd-php',
3560              'phtml' => 'application/x-httpd-php',
3561              'phps'  => 'application/x-httpd-php-source',
3562              'swf'   => 'application/x-shockwave-flash',
3563              'sit'   => 'application/x-stuffit',
3564              'tar'   => 'application/x-tar',
3565              'tgz'   => 'application/x-tar',
3566              'xht'   => 'application/xhtml+xml',
3567              'xhtml' => 'application/xhtml+xml',
3568              'zip'   => 'application/zip',
3569              'mid'   => 'audio/midi',
3570              'midi'  => 'audio/midi',
3571              'mp2'   => 'audio/mpeg',
3572              'mp3'   => 'audio/mpeg',
3573              'mpga'  => 'audio/mpeg',
3574              'aif'   => 'audio/x-aiff',
3575              'aifc'  => 'audio/x-aiff',
3576              'aiff'  => 'audio/x-aiff',
3577              'ram'   => 'audio/x-pn-realaudio',
3578              'rm'    => 'audio/x-pn-realaudio',
3579              'rpm'   => 'audio/x-pn-realaudio-plugin',
3580              'ra'    => 'audio/x-realaudio',
3581              'wav'   => 'audio/x-wav',
3582              'bmp'   => 'image/bmp',
3583              'gif'   => 'image/gif',
3584              'jpeg'  => 'image/jpeg',
3585              'jpe'   => 'image/jpeg',
3586              'jpg'   => 'image/jpeg',
3587              'png'   => 'image/png',
3588              'tiff'  => 'image/tiff',
3589              'tif'   => 'image/tiff',
3590              'eml'   => 'message/rfc822',
3591              'css'   => 'text/css',
3592              'html'  => 'text/html',
3593              'htm'   => 'text/html',
3594              'shtml' => 'text/html',
3595              'log'   => 'text/plain',
3596              'text'  => 'text/plain',
3597              'txt'   => 'text/plain',
3598              'rtx'   => 'text/richtext',
3599              'rtf'   => 'text/rtf',
3600              'vcf'   => 'text/vcard',
3601              'vcard' => 'text/vcard',
3602              'xml'   => 'text/xml',
3603              'xsl'   => 'text/xml',
3604              'mpeg'  => 'video/mpeg',
3605              'mpe'   => 'video/mpeg',
3606              'mpg'   => 'video/mpeg',
3607              'mov'   => 'video/quicktime',
3608              'qt'    => 'video/quicktime',
3609              'rv'    => 'video/vnd.rn-realvideo',
3610              'avi'   => 'video/x-msvideo',
3611              'movie' => 'video/x-sgi-movie'
3612          );
3613          if (array_key_exists(strtolower($ext), $mimes)) {
3614              return $mimes[strtolower($ext)];
3615          }
3616          return 'application/octet-stream';
3617      }
3618  
3619      /**
3620       * Map a file name to a MIME type.
3621       * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
3622       * @param string $filename A file name or full path, does not need to exist as a file
3623       * @return string
3624       * @static
3625       */
3626      public static function filenameToType($filename)
3627      {
3628          // In case the path is a URL, strip any query string before getting extension
3629          $qpos = strpos($filename, '?');
3630          if (false !== $qpos) {
3631              $filename = substr($filename, 0, $qpos);
3632          }
3633          $pathinfo = self::mb_pathinfo($filename);
3634          return self::_mime_types($pathinfo['extension']);
3635      }
3636  
3637      /**
3638       * Multi-byte-safe pathinfo replacement.
3639       * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
3640       * Works similarly to the one in PHP >= 5.2.0
3641       * @link http://www.php.net/manual/en/function.pathinfo.php#107461
3642       * @param string $path A filename or path, does not need to exist as a file
3643       * @param integer|string $options Either a PATHINFO_* constant,
3644       *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
3645       * @return string|array
3646       * @static
3647       */
3648      public static function mb_pathinfo($path, $options = null)
3649      {
3650          $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3651          $pathinfo = array();
3652          if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3653              if (array_key_exists(1, $pathinfo)) {
3654                  $ret['dirname'] = $pathinfo[1];
3655              }
3656              if (array_key_exists(2, $pathinfo)) {
3657                  $ret['basename'] = $pathinfo[2];
3658              }
3659              if (array_key_exists(5, $pathinfo)) {
3660                  $ret['extension'] = $pathinfo[5];
3661              }
3662              if (array_key_exists(3, $pathinfo)) {
3663                  $ret['filename'] = $pathinfo[3];
3664              }
3665          }
3666          switch ($options) {
3667              case PATHINFO_DIRNAME:
3668              case 'dirname':
3669                  return $ret['dirname'];
3670              case PATHINFO_BASENAME:
3671              case 'basename':
3672                  return $ret['basename'];
3673              case PATHINFO_EXTENSION:
3674              case 'extension':
3675                  return $ret['extension'];
3676              case PATHINFO_FILENAME:
3677              case 'filename':
3678                  return $ret['filename'];
3679              default:
3680                  return $ret;
3681          }
3682      }
3683  
3684      /**
3685       * Set or reset instance properties.
3686       * You should avoid this function - it's more verbose, less efficient, more error-prone and
3687       * harder to debug than setting properties directly.
3688       * Usage Example:
3689       * `$mail->set('SMTPSecure', 'tls');`
3690       *   is the same as:
3691       * `$mail->SMTPSecure = 'tls';`
3692       * @access public
3693       * @param string $name The property name to set
3694       * @param mixed $value The value to set the property to
3695       * @return boolean
3696       * @TODO Should this not be using the __set() magic function?
3697       */
3698      public function set($name, $value = '')
3699      {
3700          if (property_exists($this, $name)) {
3701              $this->$name = $value;
3702              return true;
3703          } else {
3704              $this->setError($this->lang('variable_set') . $name);
3705              return false;
3706          }
3707      }
3708  
3709      /**
3710       * Strip newlines to prevent header injection.
3711       * @access public
3712       * @param string $str
3713       * @return string
3714       */
3715      public function secureHeader($str)
3716      {
3717          return trim(str_replace(array("\r", "\n"), '', $str));
3718      }
3719  
3720      /**
3721       * Normalize line breaks in a string.
3722       * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
3723       * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
3724       * @param string $text
3725       * @param string $breaktype What kind of line break to use, defaults to CRLF
3726       * @return string
3727       * @access public
3728       * @static
3729       */
3730      public static function normalizeBreaks($text, $breaktype = "\r\n")
3731      {
3732          return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3733      }
3734  
3735      /**
3736       * Set the public and private key files and password for S/MIME signing.
3737       * @access public
3738       * @param string $cert_filename
3739       * @param string $key_filename
3740       * @param string $key_pass Password for private key
3741       * @param string $extracerts_filename Optional path to chain certificate
3742       */
3743      public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3744      {
3745          $this->sign_cert_file = $cert_filename;
3746          $this->sign_key_file = $key_filename;
3747          $this->sign_key_pass = $key_pass;
3748          $this->sign_extracerts_file = $extracerts_filename;
3749      }
3750  
3751      /**
3752       * Quoted-Printable-encode a DKIM header.
3753       * @access public
3754       * @param string $txt
3755       * @return string
3756       */
3757      public function DKIM_QP($txt)
3758      {
3759          $line = '';
3760          for ($i = 0; $i < strlen($txt); $i++) {
3761              $ord = ord($txt[$i]);
3762              if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3763                  $line .= $txt[$i];
3764              } else {
3765                  $line .= '=' . sprintf('%02X', $ord);
3766              }
3767          }
3768          return $line;
3769      }
3770  
3771      /**
3772       * Generate a DKIM signature.
3773       * @access public
3774       * @param string $signHeader
3775       * @throws phpmailerException
3776       * @return string The DKIM signature value
3777       */
3778      public function DKIM_Sign($signHeader)
3779      {
3780          if (!defined('PKCS7_TEXT')) {
3781              if ($this->exceptions) {
3782                  throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3783              }
3784              return '';
3785          }
3786          $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3787          if ('' != $this->DKIM_passphrase) {
3788              $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3789          } else {
3790              $privKey = openssl_pkey_get_private($privKeyStr);
3791          }
3792          //Workaround for missing digest algorithms in old PHP & OpenSSL versions
3793          //@link http://stackoverflow.com/a/11117338/333340
3794          if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3795              in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3796              if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3797                  openssl_pkey_free($privKey);
3798                  return base64_encode($signature);
3799              }
3800          } else {
3801              $pinfo = openssl_pkey_get_details($privKey);
3802              $hash = hash('sha256', $signHeader);
3803              //'Magic' constant for SHA256 from RFC3447
3804              //@link https://tools.ietf.org/html/rfc3447#page-43
3805              $t = '3031300d060960864801650304020105000420' . $hash;
3806              $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3807              $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3808  
3809              if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3810                  openssl_pkey_free($privKey);
3811                  return base64_encode($signature);
3812              }
3813          }
3814          openssl_pkey_free($privKey);
3815          return '';
3816      }
3817  
3818      /**
3819       * Generate a DKIM canonicalization header.
3820       * @access public
3821       * @param string $signHeader Header
3822       * @return string
3823       */
3824      public function DKIM_HeaderC($signHeader)
3825      {
3826          $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3827          $lines = explode("\r\n", $signHeader);
3828          foreach ($lines as $key => $line) {
3829              list($heading, $value) = explode(':', $line, 2);
3830              $heading = strtolower($heading);
3831              $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
3832              $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3833          }
3834          $signHeader = implode("\r\n", $lines);
3835          return $signHeader;
3836      }
3837  
3838      /**
3839       * Generate a DKIM canonicalization body.
3840       * @access public
3841       * @param string $body Message Body
3842       * @return string
3843       */
3844      public function DKIM_BodyC($body)
3845      {
3846          if ($body == '') {
3847              return "\r\n";
3848          }
3849          // stabilize line endings
3850          $body = str_replace("\r\n", "\n", $body);
3851          $body = str_replace("\n", "\r\n", $body);
3852          // END stabilize line endings
3853          while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3854              $body = substr($body, 0, strlen($body) - 2);
3855          }
3856          return $body;
3857      }
3858  
3859      /**
3860       * Create the DKIM header and body in a new message header.
3861       * @access public
3862       * @param string $headers_line Header lines
3863       * @param string $subject Subject
3864       * @param string $body Body
3865       * @return string
3866       */
3867      public function DKIM_Add($headers_line, $subject, $body)
3868      {
3869          $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
3870          $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3871          $DKIMquery = 'dns/txt'; // Query method
3872          $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3873          $subject_header = "Subject: $subject";
3874          $headers = explode($this->LE, $headers_line);
3875          $from_header = '';
3876          $to_header = '';
3877          $date_header = '';
3878          $current = '';
3879          foreach ($headers as $header) {
3880              if (strpos($header, 'From:') === 0) {
3881                  $from_header = $header;
3882                  $current = 'from_header';
3883              } elseif (strpos($header, 'To:') === 0) {
3884                  $to_header = $header;
3885                  $current = 'to_header';
3886              } elseif (strpos($header, 'Date:') === 0) {
3887                  $date_header = $header;
3888                  $current = 'date_header';
3889              } else {
3890                  if (!empty($$current) && strpos($header, ' =?') === 0) {
3891                      $$current .= $header;
3892                  } else {
3893                      $current = '';
3894                  }
3895              }
3896          }
3897          $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3898          $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3899          $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3900          $subject = str_replace(
3901              '|',
3902              '=7C',
3903              $this->DKIM_QP($subject_header)
3904          ); // Copied header fields (dkim-quoted-printable)
3905          $body = $this->DKIM_BodyC($body);
3906          $DKIMlen = strlen($body); // Length of body
3907          $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
3908          if ('' == $this->DKIM_identity) {
3909              $ident = '';
3910          } else {
3911              $ident = ' i=' . $this->DKIM_identity . ';';
3912          }
3913          $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3914              $DKIMsignatureType . '; q=' .
3915              $DKIMquery . '; l=' .
3916              $DKIMlen . '; s=' .
3917              $this->DKIM_selector .
3918              ";\r\n" .
3919              "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3920              "\th=From:To:Date:Subject;\r\n" .
3921              "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3922              "\tz=$from\r\n" .
3923              "\t|$to\r\n" .
3924              "\t|$date\r\n" .
3925              "\t|$subject;\r\n" .
3926              "\tbh=" . $DKIMb64 . ";\r\n" .
3927              "\tb=";
3928          $toSign = $this->DKIM_HeaderC(
3929              $from_header . "\r\n" .
3930              $to_header . "\r\n" .
3931              $date_header . "\r\n" .
3932              $subject_header . "\r\n" .
3933              $dkimhdrs
3934          );
3935          $signed = $this->DKIM_Sign($toSign);
3936          return $dkimhdrs . $signed . "\r\n";
3937      }
3938  
3939      /**
3940       * Detect if a string contains a line longer than the maximum line length allowed.
3941       * @param string $str
3942       * @return boolean
3943       * @static
3944       */
3945      public static function hasLineLongerThanMax($str)
3946      {
3947          //+2 to include CRLF line break for a 1000 total
3948          return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3949      }
3950  
3951      /**
3952       * Allows for public read access to 'to' property.
3953       * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3954       * @access public
3955       * @return array
3956       */
3957      public function getToAddresses()
3958      {
3959          return $this->to;
3960      }
3961  
3962      /**
3963       * Allows for public read access to 'cc' property.
3964       * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3965       * @access public
3966       * @return array
3967       */
3968      public function getCcAddresses()
3969      {
3970          return $this->cc;
3971      }
3972  
3973      /**
3974       * Allows for public read access to 'bcc' property.
3975       * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3976       * @access public
3977       * @return array
3978       */
3979      public function getBccAddresses()
3980      {
3981          return $this->bcc;
3982      }
3983  
3984      /**
3985       * Allows for public read access to 'ReplyTo' property.
3986       * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3987       * @access public
3988       * @return array
3989       */
3990      public function getReplyToAddresses()
3991      {
3992          return $this->ReplyTo;
3993      }
3994  
3995      /**
3996       * Allows for public read access to 'all_recipients' property.
3997       * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3998       * @access public
3999       * @return array
4000       */
4001      public function getAllRecipientAddresses()
4002      {
4003          return $this->all_recipients;
4004      }
4005  
4006      /**
4007       * Perform a callback.
4008       * @param boolean $isSent
4009       * @param array $to
4010       * @param array $cc
4011       * @param array $bcc
4012       * @param string $subject
4013       * @param string $body
4014       * @param string $from
4015       */
4016      protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4017      {
4018          if (!empty($this->action_function) && is_callable($this->action_function)) {
4019              $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4020              call_user_func_array($this->action_function, $params);
4021          }
4022      }
4023  }
4024  
4025  /**
4026   * PHPMailer exception handler
4027   * @package PHPMailer
4028   */
4029  class phpmailerException extends Exception
4030  {
4031      /**
4032       * Prettify error message output
4033       * @return string
4034       */
4035      public function errorMessage()
4036      {
4037          $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
4038          return $errorMsg;
4039      }
4040  }


Generated: Mon Jul 22 01:00:03 2019 Cross-referenced by PHPXref 0.7.1