PageRenderTime 18ms CodeModel.GetById 5ms app.highlight 93ms RepoModel.GetById 1ms app.codeStats 1ms

/vendor/phpmailer/phpmailer/class.phpmailer.php

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