WordPress.org

Make WordPress Core

Ticket #40472: 40472v5.diff

File 40472v5.diff, 338.1 KB (added by MattyRob, 18 months ago)
  • src/wp-includes/class-phpmailer.php

     
    2727 */
    2828class PHPMailer
    2929{
    30     /**
    31     * The PHPMailer Version number.
    32     * @var string
    33     */
    34     public $Version = '5.2.22';
     30        /**
     31        * The PHPMailer Version number.
     32        * @var string
     33        */
     34        public $Version = '5.2.26';
    3535
    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;
     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;
    4343
    44     /**
    45     * The character set of the message.
    46     * @var string
    47     */
    48     public $CharSet = 'iso-8859-1';
     44        /**
     45        * The character set of the message.
     46        * @var string
     47        */
     48        public $CharSet = 'iso-8859-1';
    4949
    50     /**
    51     * The MIME Content-type of the message.
    52     * @var string
    53     */
    54     public $ContentType = 'text/plain';
     50        /**
     51        * The MIME Content-type of the message.
     52        * @var string
     53        */
     54        public $ContentType = 'text/plain';
    5555
    56     /**
    57     * The message encoding.
    58     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
    59     * @var string
    60     */
    61     public $Encoding = '8bit';
     56        /**
     57        * The message encoding.
     58        * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
     59        * @var string
     60        */
     61        public $Encoding = '8bit';
    6262
    63     /**
    64     * Holds the most recent mailer error message.
    65     * @var string
    66     */
    67     public $ErrorInfo = '';
     63        /**
     64        * Holds the most recent mailer error message.
     65        * @var string
     66        */
     67        public $ErrorInfo = '';
    6868
    69     /**
    70     * The From email address for the message.
    71     * @var string
    72     */
    73     public $From = 'root@localhost';
     69        /**
     70        * The From email address for the message.
     71        * @var string
     72        */
     73        public $From = 'root@localhost';
    7474
    75     /**
    76     * The From name of the message.
    77     * @var string
    78     */
    79     public $FromName = 'Root User';
     75        /**
     76        * The From name of the message.
     77        * @var string
     78        */
     79        public $FromName = 'Root User';
    8080
    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 = '';
     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 = '';
    8787
    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 = '';
     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 = '';
    9797
    98     /**
    99     * The Subject of the message.
    100     * @var string
    101     */
    102     public $Subject = '';
     98        /**
     99        * The Subject of the message.
     100        * @var string
     101        */
     102        public $Subject = '';
    103103
    104     /**
    105     * An HTML or plain text message body.
    106     * If HTML then call isHTML(true).
    107     * @var string
    108     */
    109     public $Body = '';
     104        /**
     105        * An HTML or plain text message body.
     106        * If HTML then call isHTML(true).
     107        * @var string
     108        */
     109        public $Body = '';
    110110
    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 = '';
     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 = '';
    119119
    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 = '';
     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 = '';
    129129
    130     /**
    131     * The complete compiled MIME message body.
    132     * @access protected
    133     * @var string
    134     */
    135     protected $MIMEBody = '';
     130        /**
     131        * The complete compiled MIME message body.
     132        * @access protected
     133        * @var string
     134        */
     135        protected $MIMEBody = '';
    136136
    137     /**
    138     * The complete compiled MIME message headers.
    139     * @var string
    140     * @access protected
    141     */
    142     protected $MIMEHeader = '';
     137        /**
     138        * The complete compiled MIME message headers.
     139        * @var string
     140        * @access protected
     141        */
     142        protected $MIMEHeader = '';
    143143
    144     /**
    145     * Extra headers that createHeader() doesn't fold in.
    146     * @var string
    147     * @access protected
    148     */
    149     protected $mailHeader = '';
     144        /**
     145        * Extra headers that createHeader() doesn't fold in.
     146        * @var string
     147        * @access protected
     148        */
     149        protected $mailHeader = '';
    150150
    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;
     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;
    157157
    158     /**
    159     * Which method to use to send mail.
    160     * Options: "mail", "sendmail", or "smtp".
    161     * @var string
    162     */
    163     public $Mailer = 'mail';
     158        /**
     159        * Which method to use to send mail.
     160        * Options: "mail", "sendmail", or "smtp".
     161        * @var string
     162        */
     163        public $Mailer = 'mail';
    164164
    165     /**
    166     * The path to the sendmail program.
    167     * @var string
    168     */
    169     public $Sendmail = '/usr/sbin/sendmail';
     165        /**
     166        * The path to the sendmail program.
     167        * @var string
     168        */
     169        public $Sendmail = '/usr/sbin/sendmail';
    170170
    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;
     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;
    177177
    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 = '';
     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 = '';
    185185
    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 = '';
     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 = '';
    191191
    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 = '';
     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 = '';
    200200
    201     /**
    202     * An ID to be used in the Message-ID header.
    203     * If empty, a unique id will be generated.
    204     * You can set your own, but it must be in the format "<id@domain>",
    205     * as defined in RFC5322 section 3.6.4 or it will be ignored.
    206     * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
    207     * @var string
    208     */
    209     public $MessageID = '';
     201        /**
     202        * An ID to be used in the Message-ID header.
     203        * If empty, a unique id will be generated.
     204        * You can set your own, but it must be in the format "<id@domain>",
     205        * as defined in RFC5322 section 3.6.4 or it will be ignored.
     206        * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
     207        * @var string
     208        */
     209        public $MessageID = '';
    210210
    211     /**
    212     * The message Date to be used in the Date header.
    213     * If empty, the current date will be added.
    214     * @var string
    215     */
    216     public $MessageDate = '';
     211        /**
     212        * The message Date to be used in the Date header.
     213        * If empty, the current date will be added.
     214        * @var string
     215        */
     216        public $MessageDate = '';
    217217
    218     /**
    219     * SMTP hosts.
    220     * Either a single hostname or multiple semicolon-delimited hostnames.
    221     * You can also specify a different port
    222     * for each host by using this format: [hostname:port]
    223     * (e.g. "smtp1.example.com:25;smtp2.example.com").
    224     * You can also specify encryption type, for example:
    225     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
    226     * Hosts will be tried in order.
    227     * @var string
    228     */
    229     public $Host = 'localhost';
     218        /**
     219        * SMTP hosts.
     220        * Either a single hostname or multiple semicolon-delimited hostnames.
     221        * You can also specify a different port
     222        * for each host by using this format: [hostname:port]
     223        * (e.g. "smtp1.example.com:25;smtp2.example.com").
     224        * You can also specify encryption type, for example:
     225        * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
     226        * Hosts will be tried in order.
     227        * @var string
     228        */
     229        public $Host = 'localhost';
    230230
    231     /**
    232     * The default SMTP server port.
    233     * @var integer
    234     * @TODO Why is this needed when the SMTP class takes care of it?
    235     */
    236     public $Port = 25;
     231        /**
     232        * The default SMTP server port.
     233        * @var integer
     234        * @TODO Why is this needed when the SMTP class takes care of it?
     235        */
     236        public $Port = 25;
    237237
    238     /**
    239     * The SMTP HELO of the message.
    240     * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
    241     * one with the same method described above for $Hostname.
    242     * @var string
    243     * @see PHPMailer::$Hostname
    244     */
    245     public $Helo = '';
     238        /**
     239        * The SMTP HELO of the message.
     240        * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
     241        * one with the same method described above for $Hostname.
     242        * @var string
     243        * @see PHPMailer::$Hostname
     244        */
     245        public $Helo = '';
    246246
    247     /**
    248     * What kind of encryption to use on the SMTP connection.
    249     * Options: '', 'ssl' or 'tls'
    250     * @var string
    251     */
    252     public $SMTPSecure = '';
     247        /**
     248        * What kind of encryption to use on the SMTP connection.
     249        * Options: '', 'ssl' or 'tls'
     250        * @var string
     251        */
     252        public $SMTPSecure = '';
    253253
    254     /**
    255     * Whether to enable TLS encryption automatically if a server supports it,
    256     * even if `SMTPSecure` is not set to 'tls'.
    257     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
    258     * @var boolean
    259     */
    260     public $SMTPAutoTLS = true;
     254        /**
     255        * Whether to enable TLS encryption automatically if a server supports it,
     256        * even if `SMTPSecure` is not set to 'tls'.
     257        * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
     258        * @var boolean
     259        */
     260        public $SMTPAutoTLS = true;
    261261
    262     /**
    263     * Whether to use SMTP authentication.
    264     * Uses the Username and Password properties.
    265     * @var boolean
    266     * @see PHPMailer::$Username
    267     * @see PHPMailer::$Password
    268     */
    269     public $SMTPAuth = false;
     262        /**
     263        * Whether to use SMTP authentication.
     264        * Uses the Username and Password properties.
     265        * @var boolean
     266        * @see PHPMailer::$Username
     267        * @see PHPMailer::$Password
     268        */
     269        public $SMTPAuth = false;
    270270
    271     /**
    272     * Options array passed to stream_context_create when connecting via SMTP.
    273     * @var array
    274     */
    275     public $SMTPOptions = array();
     271        /**
     272        * Options array passed to stream_context_create when connecting via SMTP.
     273        * @var array
     274        */
     275        public $SMTPOptions = array();
    276276
    277     /**
    278     * SMTP username.
    279     * @var string
    280     */
    281     public $Username = '';
     277        /**
     278        * SMTP username.
     279        * @var string
     280        */
     281        public $Username = '';
    282282
    283     /**
    284     * SMTP password.
    285     * @var string
    286     */
    287     public $Password = '';
     283        /**
     284        * SMTP password.
     285        * @var string
     286        */
     287        public $Password = '';
    288288
    289     /**
    290     * SMTP auth type.
    291     * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
    292     * @var string
    293     */
    294     public $AuthType = '';
     289        /**
     290        * SMTP auth type.
     291        * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
     292        * @var string
     293        */
     294        public $AuthType = '';
    295295
    296     /**
    297     * SMTP realm.
    298     * Used for NTLM auth
    299     * @var string
    300     */
    301     public $Realm = '';
     296        /**
     297        * SMTP realm.
     298        * Used for NTLM auth
     299        * @var string
     300        */
     301        public $Realm = '';
    302302
    303     /**
    304     * SMTP workstation.
    305     * Used for NTLM auth
    306     * @var string
    307     */
    308     public $Workstation = '';
     303        /**
     304        * SMTP workstation.
     305        * Used for NTLM auth
     306        * @var string
     307        */
     308        public $Workstation = '';
    309309
    310     /**
    311     * The SMTP server timeout in seconds.
    312     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
    313     * @var integer
    314     */
    315     public $Timeout = 300;
     310        /**
     311        * The SMTP server timeout in seconds.
     312        * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     313        * @var integer
     314        */
     315        public $Timeout = 300;
    316316
    317     /**
    318     * SMTP class debug output mode.
    319     * Debug output level.
    320     * Options:
    321     * * `0` No output
    322     * * `1` Commands
    323     * * `2` Data and commands
    324     * * `3` As 2 plus connection status
    325     * * `4` Low-level data output
    326     * @var integer
    327     * @see SMTP::$do_debug
    328     */
    329     public $SMTPDebug = 0;
     317        /**
     318        * SMTP class debug output mode.
     319        * Debug output level.
     320        * Options:
     321        * * `0` No output
     322        * * `1` Commands
     323        * * `2` Data and commands
     324        * * `3` As 2 plus connection status
     325        * * `4` Low-level data output
     326        * @var integer
     327        * @see SMTP::$do_debug
     328        */
     329        public $SMTPDebug = 0;
    330330
    331     /**
    332     * How to handle debug output.
    333     * Options:
    334     * * `echo` Output plain-text as-is, appropriate for CLI
    335     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
    336     * * `error_log` Output to error log as configured in php.ini
    337     *
    338     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
    339     * <code>
    340     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
    341     * </code>
    342     * @var string|callable
    343     * @see SMTP::$Debugoutput
    344     */
    345     public $Debugoutput = 'echo';
     331        /**
     332        * How to handle debug output.
     333        * Options:
     334        * * `echo` Output plain-text as-is, appropriate for CLI
     335        * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
     336        * * `error_log` Output to error log as configured in php.ini
     337        *
     338        * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
     339        * <code>
     340        * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
     341        * </code>
     342        * @var string|callable
     343        * @see SMTP::$Debugoutput
     344        */
     345        public $Debugoutput = 'echo';
    346346
    347     /**
    348     * Whether to keep SMTP connection open after each message.
    349     * If this is set to true then to close the connection
    350     * requires an explicit call to smtpClose().
    351     * @var boolean
    352     */
    353     public $SMTPKeepAlive = false;
     347        /**
     348        * Whether to keep SMTP connection open after each message.
     349        * If this is set to true then to close the connection
     350        * requires an explicit call to smtpClose().
     351        * @var boolean
     352        */
     353        public $SMTPKeepAlive = false;
    354354
    355     /**
    356     * Whether to split multiple to addresses into multiple messages
    357     * or send them all in one message.
    358     * Only supported in `mail` and `sendmail` transports, not in SMTP.
    359     * @var boolean
    360     */
    361     public $SingleTo = false;
     355        /**
     356        * Whether to split multiple to addresses into multiple messages
     357        * or send them all in one message.
     358        * Only supported in `mail` and `sendmail` transports, not in SMTP.
     359        * @var boolean
     360        */
     361        public $SingleTo = false;
    362362
    363     /**
    364     * Storage for addresses when SingleTo is enabled.
    365     * @var array
    366     * @TODO This should really not be public
    367     */
    368     public $SingleToArray = array();
     363        /**
     364        * Storage for addresses when SingleTo is enabled.
     365        * @var array
     366        * @TODO This should really not be public
     367        */
     368        public $SingleToArray = array();
    369369
    370     /**
    371     * Whether to generate VERP addresses on send.
    372     * Only applicable when sending via SMTP.
    373     * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
    374     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
    375     * @var boolean
    376     */
    377     public $do_verp = false;
     370        /**
     371        * Whether to generate VERP addresses on send.
     372        * Only applicable when sending via SMTP.
     373        * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
     374        * @link http://www.postfix.org/VERP_README.html Postfix VERP info
     375        * @var boolean
     376        */
     377        public $do_verp = false;
    378378
    379     /**
    380     * Whether to allow sending messages with an empty body.
    381     * @var boolean
    382     */
    383     public $AllowEmpty = false;
     379        /**
     380        * Whether to allow sending messages with an empty body.
     381        * @var boolean
     382        */
     383        public $AllowEmpty = false;
    384384
    385     /**
    386     * The default line ending.
    387     * @note The default remains "\n". We force CRLF where we know
    388      *        it must be used via self::CRLF.
    389     * @var string
    390     */
    391     public $LE = "\n";
     385        /**
     386        * The default line ending.
     387        * @note The default remains "\n". We force CRLF where we know
     388         *              it must be used via self::CRLF.
     389        * @var string
     390        */
     391        public $LE = "\n";
    392392
    393     /**
    394     * DKIM selector.
    395     * @var string
    396     */
    397     public $DKIM_selector = '';
     393        /**
     394        * DKIM selector.
     395        * @var string
     396        */
     397        public $DKIM_selector = '';
    398398
    399     /**
    400     * DKIM Identity.
    401     * Usually the email address used as the source of the email.
    402     * @var string
    403     */
    404     public $DKIM_identity = '';
     399        /**
     400        * DKIM Identity.
     401        * Usually the email address used as the source of the email.
     402        * @var string
     403        */
     404        public $DKIM_identity = '';
    405405
    406     /**
    407     * DKIM passphrase.
    408     * Used if your key is encrypted.
    409     * @var string
    410     */
    411     public $DKIM_passphrase = '';
     406        /**
     407        * DKIM passphrase.
     408        * Used if your key is encrypted.
     409        * @var string
     410        */
     411        public $DKIM_passphrase = '';
    412412
    413     /**
    414     * DKIM signing domain name.
    415     * @example 'example.com'
    416     * @var string
    417     */
    418     public $DKIM_domain = '';
     413        /**
     414        * DKIM signing domain name.
     415        * @example 'example.com'
     416        * @var string
     417        */
     418        public $DKIM_domain = '';
    419419
    420     /**
    421     * DKIM private key file path.
    422     * @var string
    423     */
    424     public $DKIM_private = '';
     420        /**
     421        * DKIM private key file path.
     422        * @var string
     423        */
     424        public $DKIM_private = '';
    425425
    426     /**
    427     * DKIM private key string.
    428     * If set, takes precedence over `$DKIM_private`.
    429     * @var string
    430     */
    431     public $DKIM_private_string = '';
     426        /**
     427        * DKIM private key string.
     428        * If set, takes precedence over `$DKIM_private`.
     429        * @var string
     430        */
     431        public $DKIM_private_string = '';
    432432
    433     /**
    434     * Callback Action function name.
    435     *
    436     * The function that handles the result of the send email action.
    437     * It is called out by send() for each email sent.
    438     *
    439     * Value can be any php callable: http://www.php.net/is_callable
    440     *
    441     * Parameters:
    442      *   boolean $result        result of the send action
    443      *   string  $to            email address of the recipient
    444      *   string  $cc            cc email addresses
    445      *   string  $bcc           bcc email addresses
    446      *   string  $subject       the subject
    447      *   string  $body          the email body
    448      *   string  $from          email address of sender
    449     * @var string
    450     */
    451     public $action_function = '';
     433        /**
     434        * Callback Action function name.
     435        *
     436        * The function that handles the result of the send email action.
     437        * It is called out by send() for each email sent.
     438        *
     439        * Value can be any php callable: http://www.php.net/is_callable
     440        *
     441        * Parameters:
     442         *   boolean $result            result of the send action
     443         *   array   $to                        email addresses of the recipients
     444         *   array   $cc                        cc email addresses
     445         *   array   $bcc                  bcc email addresses
     446         *   string  $subject      the subject
     447         *   string  $body                the email body
     448         *   string  $from                email address of sender
     449        * @var string
     450        */
     451        public $action_function = '';
    452452
    453     /**
    454     * What to put in the X-Mailer header.
    455     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
    456     * @var string
    457     */
    458     public $XMailer = '';
     453        /**
     454        * What to put in the X-Mailer header.
     455        * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
     456        * @var string
     457        */
     458        public $XMailer = '';
    459459
    460     /**
    461     * Which validator to use by default when validating email addresses.
    462     * May be a callable to inject your own validator, but there are several built-in validators.
    463     * @see PHPMailer::validateAddress()
    464     * @var string|callable
    465     * @static
    466     */
    467     public static $validator = 'auto';
     460        /**
     461        * Which validator to use by default when validating email addresses.
     462        * May be a callable to inject your own validator, but there are several built-in validators.
     463        * @see PHPMailer::validateAddress()
     464        * @var string|callable
     465        * @static
     466        */
     467        public static $validator = 'auto';
    468468
    469     /**
    470     * An instance of the SMTP sender class.
    471     * @var SMTP
    472     * @access protected
    473     */
    474     protected $smtp = null;
     469        /**
     470        * An instance of the SMTP sender class.
     471        * @var SMTP
     472        * @access protected
     473        */
     474        protected $smtp = null;
    475475
    476     /**
    477     * The array of 'to' names and addresses.
    478     * @var array
    479     * @access protected
    480     */
    481     protected $to = array();
     476        /**
     477        * The array of 'to' names and addresses.
     478        * @var array
     479        * @access protected
     480        */
     481        protected $to = array();
    482482
    483     /**
    484     * The array of 'cc' names and addresses.
    485     * @var array
    486     * @access protected
    487     */
    488     protected $cc = array();
     483        /**
     484        * The array of 'cc' names and addresses.
     485        * @var array
     486        * @access protected
     487        */
     488        protected $cc = array();
    489489
    490     /**
    491     * The array of 'bcc' names and addresses.
    492     * @var array
    493     * @access protected
    494     */
    495     protected $bcc = array();
     490        /**
     491        * The array of 'bcc' names and addresses.
     492        * @var array
     493        * @access protected
     494        */
     495        protected $bcc = array();
    496496
    497     /**
    498     * The array of reply-to names and addresses.
    499     * @var array
    500     * @access protected
    501     */
    502     protected $ReplyTo = array();
     497        /**
     498        * The array of reply-to names and addresses.
     499        * @var array
     500        * @access protected
     501        */
     502        protected $ReplyTo = array();
    503503
    504     /**
    505     * An array of all kinds of addresses.
    506     * Includes all of $to, $cc, $bcc
    507     * @var array
    508     * @access protected
    509     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
    510     */
    511     protected $all_recipients = array();
     504        /**
     505        * An array of all kinds of addresses.
     506        * Includes all of $to, $cc, $bcc
     507        * @var array
     508        * @access protected
     509        * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
     510        */
     511        protected $all_recipients = array();
    512512
    513     /**
    514     * An array of names and addresses queued for validation.
    515     * In send(), valid and non duplicate entries are moved to $all_recipients
    516     * and one of $to, $cc, or $bcc.
    517     * This array is used only for addresses with IDN.
    518     * @var array
    519     * @access protected
    520     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
    521     * @see PHPMailer::$all_recipients
    522     */
    523     protected $RecipientsQueue = array();
     513        /**
     514        * An array of names and addresses queued for validation.
     515        * In send(), valid and non duplicate entries are moved to $all_recipients
     516        * and one of $to, $cc, or $bcc.
     517        * This array is used only for addresses with IDN.
     518        * @var array
     519        * @access protected
     520        * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
     521        * @see PHPMailer::$all_recipients
     522        */
     523        protected $RecipientsQueue = array();
    524524
    525     /**
    526     * An array of reply-to names and addresses queued for validation.
    527     * In send(), valid and non duplicate entries are moved to $ReplyTo.
    528     * This array is used only for addresses with IDN.
    529     * @var array
    530     * @access protected
    531     * @see PHPMailer::$ReplyTo
    532     */
    533     protected $ReplyToQueue = array();
     525        /**
     526        * An array of reply-to names and addresses queued for validation.
     527        * In send(), valid and non duplicate entries are moved to $ReplyTo.
     528        * This array is used only for addresses with IDN.
     529        * @var array
     530        * @access protected
     531        * @see PHPMailer::$ReplyTo
     532        */
     533        protected $ReplyToQueue = array();
    534534
    535     /**
    536     * The array of attachments.
    537     * @var array
    538     * @access protected
    539     */
    540     protected $attachment = array();
     535        /**
     536        * The array of attachments.
     537        * @var array
     538        * @access protected
     539        */
     540        protected $attachment = array();
    541541
    542     /**
    543     * The array of custom headers.
    544     * @var array
    545     * @access protected
    546     */
    547     protected $CustomHeader = array();
     542        /**
     543        * The array of custom headers.
     544        * @var array
     545        * @access protected
     546        */
     547        protected $CustomHeader = array();
    548548
    549     /**
    550     * The most recent Message-ID (including angular brackets).
    551     * @var string
    552     * @access protected
    553     */
    554     protected $lastMessageID = '';
     549        /**
     550        * The most recent Message-ID (including angular brackets).
     551        * @var string
     552        * @access protected
     553        */
     554        protected $lastMessageID = '';
    555555
    556     /**
    557     * The message's MIME type.
    558     * @var string
    559     * @access protected
    560     */
    561     protected $message_type = '';
     556        /**
     557        * The message's MIME type.
     558        * @var string
     559        * @access protected
     560        */
     561        protected $message_type = '';
    562562
    563     /**
    564     * The array of MIME boundary strings.
    565     * @var array
    566     * @access protected
    567     */
    568     protected $boundary = array();
     563        /**
     564        * The array of MIME boundary strings.
     565        * @var array
     566        * @access protected
     567        */
     568        protected $boundary = array();
    569569
    570     /**
    571     * The array of available languages.
    572     * @var array
    573     * @access protected
    574     */
    575     protected $language = array();
     570        /**
     571        * The array of available languages.
     572        * @var array
     573        * @access protected
     574        */
     575        protected $language = array();
    576576
    577     /**
    578     * The number of errors encountered.
    579     * @var integer
    580     * @access protected
    581     */
    582     protected $error_count = 0;
     577        /**
     578        * The number of errors encountered.
     579        * @var integer
     580        * @access protected
     581        */
     582        protected $error_count = 0;
    583583
    584     /**
    585     * The S/MIME certificate file path.
    586     * @var string
    587     * @access protected
    588     */
    589     protected $sign_cert_file = '';
     584        /**
     585        * The S/MIME certificate file path.
     586        * @var string
     587        * @access protected
     588        */
     589        protected $sign_cert_file = '';
    590590
    591     /**
    592     * The S/MIME key file path.
    593     * @var string
    594     * @access protected
    595     */
    596     protected $sign_key_file = '';
     591        /**
     592        * The S/MIME key file path.
     593        * @var string
     594        * @access protected
     595        */
     596        protected $sign_key_file = '';
    597597
    598     /**
    599     * The optional S/MIME extra certificates ("CA Chain") file path.
    600     * @var string
    601     * @access protected
    602     */
    603     protected $sign_extracerts_file = '';
     598        /**
     599        * The optional S/MIME extra certificates ("CA Chain") file path.
     600        * @var string
     601        * @access protected
     602        */
     603        protected $sign_extracerts_file = '';
    604604
    605     /**
    606     * The S/MIME password for the key.
    607     * Used only if the key is encrypted.
    608     * @var string
    609     * @access protected
    610     */
    611     protected $sign_key_pass = '';
     605        /**
     606        * The S/MIME password for the key.
     607        * Used only if the key is encrypted.
     608        * @var string
     609        * @access protected
     610        */
     611        protected $sign_key_pass = '';
    612612
    613     /**
    614     * Whether to throw exceptions for errors.
    615     * @var boolean
    616     * @access protected
    617     */
    618     protected $exceptions = false;
     613        /**
     614        * Whether to throw exceptions for errors.
     615        * @var boolean
     616        * @access protected
     617        */
     618        protected $exceptions = false;
    619619
    620     /**
    621     * Unique ID used for message ID and boundaries.
    622     * @var string
    623     * @access protected
    624     */
    625     protected $uniqueid = '';
     620        /**
     621        * Unique ID used for message ID and boundaries.
     622        * @var string
     623        * @access protected
     624        */
     625        protected $uniqueid = '';
    626626
    627     /**
    628     * Error severity: message only, continue processing.
    629     */
    630     const STOP_MESSAGE = 0;
     627        /**
     628        * Error severity: message only, continue processing.
     629        */
     630        const STOP_MESSAGE = 0;
    631631
    632     /**
    633     * Error severity: message, likely ok to continue processing.
    634     */
    635     const STOP_CONTINUE = 1;
     632        /**
     633        * Error severity: message, likely ok to continue processing.
     634        */
     635        const STOP_CONTINUE = 1;
    636636
    637     /**
    638     * Error severity: message, plus full stop, critical error reached.
    639     */
    640     const STOP_CRITICAL = 2;
     637        /**
     638        * Error severity: message, plus full stop, critical error reached.
     639        */
     640        const STOP_CRITICAL = 2;
    641641
    642     /**
    643     * SMTP RFC standard line ending.
    644     */
    645     const CRLF = "\r\n";
     642        /**
     643        * SMTP RFC standard line ending.
     644        */
     645        const CRLF = "\r\n";
    646646
    647     /**
    648     * The maximum line length allowed by RFC 2822 section 2.1.1
    649     * @var integer
    650     */
    651     const MAX_LINE_LENGTH = 998;
     647        /**
     648        * The maximum line length allowed by RFC 2822 section 2.1.1
     649        * @var integer
     650        */
     651        const MAX_LINE_LENGTH = 998;
    652652
    653     /**
    654      * Constructor.
    655      * @param boolean $exceptions Should we throw external exceptions?
    656      */
    657     public function __construct($exceptions = null)
    658     {
    659         if ($exceptions !== null) {
    660             $this->exceptions = (boolean)$exceptions;
    661         }
    662     }
     653        /**
     654         * Constructor.
     655         * @param boolean $exceptions Should we throw external exceptions?
     656         */
     657        public function __construct($exceptions = null)
     658        {
     659                if ($exceptions !== null) {
     660                        $this->exceptions = (boolean)$exceptions;
     661                }
     662                //Pick an appropriate debug output format automatically
     663                $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
     664        }
    663665
    664     /**
    665     * Destructor.
    666     */
    667     public function __destruct()
    668     {
    669         //Close any open SMTP connection nicely
    670         $this->smtpClose();
    671     }
     666        /**
     667        * Destructor.
     668        */
     669        public function __destruct()
     670        {
     671                //Close any open SMTP connection nicely
     672                $this->smtpClose();
     673        }
    672674
    673     /**
    674     * Call mail() in a safe_mode-aware fashion.
    675     * Also, unless sendmail_path points to sendmail (or something that
    676     * claims to be sendmail), don't pass params (not a perfect fix,
    677     * but it will do)
    678     * @param string $to To
    679     * @param string $subject Subject
    680     * @param string $body Message Body
    681     * @param string $header Additional Header(s)
    682     * @param string $params Params
    683     * @access private
    684     * @return boolean
    685     */
    686     private function mailPassthru($to, $subject, $body, $header, $params)
    687     {
    688         //Check overloading of mail function to avoid double-encoding
    689         if (ini_get('mbstring.func_overload') & 1) {
    690             $subject = $this->secureHeader($subject);
    691         } else {
    692             $subject = $this->encodeHeader($this->secureHeader($subject));
    693         }
     675        /**
     676        * Call mail() in a safe_mode-aware fashion.
     677        * Also, unless sendmail_path points to sendmail (or something that
     678        * claims to be sendmail), don't pass params (not a perfect fix,
     679        * but it will do)
     680        * @param string $to To
     681        * @param string $subject Subject
     682        * @param string $body Message Body
     683        * @param string $header Additional Header(s)
     684        * @param string $params Params
     685        * @access private
     686        * @return boolean
     687        */
     688        private function mailPassthru($to, $subject, $body, $header, $params)
     689        {
     690                //Check overloading of mail function to avoid double-encoding
     691                if (ini_get('mbstring.func_overload') & 1) {
     692                        $subject = $this->secureHeader($subject);
     693                } else {
     694                        $subject = $this->encodeHeader($this->secureHeader($subject));
     695                }
    694696
    695         //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
    696         //@link http://php.net/manual/en/function.mail.php
    697         if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
    698             $result = @mail($to, $subject, $body, $header);
    699         } else {
    700             $result = @mail($to, $subject, $body, $header, $params);
    701         }
    702         return $result;
    703     }
    704     /**
    705     * Output debugging info via user-defined method.
    706     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
    707     * @see PHPMailer::$Debugoutput
    708     * @see PHPMailer::$SMTPDebug
    709     * @param string $str
    710     */
    711     protected function edebug($str)
    712     {
    713         if ($this->SMTPDebug <= 0) {
    714             return;
    715         }
    716         //Avoid clash with built-in function names
    717         if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
    718             call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
    719             return;
    720         }
    721         switch ($this->Debugoutput) {
    722             case 'error_log':
    723                 //Don't output, just log
    724                 error_log($str);
    725                 break;
    726             case 'html':
    727                 //Cleans up output a bit for a better looking, HTML-safe output
    728                 echo htmlentities(
    729                     preg_replace('/[\r\n]+/', '', $str),
    730                     ENT_QUOTES,
    731                     'UTF-8'
    732                 )
    733                 . "<br>\n";
    734                 break;
    735             case 'echo':
    736             default:
    737                 //Normalize line breaks
    738                 $str = preg_replace('/\r\n?/ms', "\n", $str);
    739                 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
    740                     "\n",
    741                     "\n                   \t                  ",
    742                     trim($str)
    743                 ) . "\n";
    744         }
    745     }
     697                //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
     698                //@link http://php.net/manual/en/function.mail.php
     699                if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
     700                        $result = @mail($to, $subject, $body, $header);
     701                } else {
     702                        $result = @mail($to, $subject, $body, $header, $params);
     703                }
     704                return $result;
     705        }
     706        /**
     707        * Output debugging info via user-defined method.
     708        * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
     709        * @see PHPMailer::$Debugoutput
     710        * @see PHPMailer::$SMTPDebug
     711        * @param string $str
     712        */
     713        protected function edebug($str)
     714        {
     715                if ($this->SMTPDebug <= 0) {
     716                        return;
     717                }
     718                //Avoid clash with built-in function names
     719                if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
     720                        call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
     721                        return;
     722                }
     723                switch ($this->Debugoutput) {
     724                        case 'error_log':
     725                                //Don't output, just log
     726                                error_log($str);
     727                                break;
     728                        case 'html':
     729                                //Cleans up output a bit for a better looking, HTML-safe output
     730                                echo htmlentities(
     731                                        preg_replace('/[\r\n]+/', '', $str),
     732                                        ENT_QUOTES,
     733                                        'UTF-8'
     734                                )
     735                                . "<br>\n";
     736                                break;
     737                        case 'echo':
     738                        default:
     739                                //Normalize line breaks
     740                                $str = preg_replace('/\r\n?/ms', "\n", $str);
     741                                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
     742                                        "\n",
     743                                        "\n                                \t                             ",
     744                                        trim($str)
     745                                ) . "\n";
     746                }
     747        }
    746748
    747     /**
    748     * Sets message type to HTML or plain.
    749     * @param boolean $isHtml True for HTML mode.
    750     * @return void
    751     */
    752     public function isHTML($isHtml = true)
    753     {
    754         if ($isHtml) {
    755             $this->ContentType = 'text/html';
    756         } else {
    757             $this->ContentType = 'text/plain';
    758         }
    759     }
     749        /**
     750        * Sets message type to HTML or plain.
     751        * @param boolean $isHtml True for HTML mode.
     752        * @return void
     753        */
     754        public function isHTML($isHtml = true)
     755        {
     756                if ($isHtml) {
     757                        $this->ContentType = 'text/html';
     758                } else {
     759                        $this->ContentType = 'text/plain';
     760                }
     761        }
    760762
    761     /**
    762     * Send messages using SMTP.
    763     * @return void
    764     */
    765     public function isSMTP()
    766     {
    767         $this->Mailer = 'smtp';
    768     }
     763        /**
     764        * Send messages using SMTP.
     765        * @return void
     766        */
     767        public function isSMTP()
     768        {
     769                $this->Mailer = 'smtp';
     770        }
    769771
    770     /**
    771     * Send messages using PHP's mail() function.
    772     * @return void
    773     */
    774     public function isMail()
    775     {
    776         $this->Mailer = 'mail';
    777     }
     772        /**
     773        * Send messages using PHP's mail() function.
     774        * @return void
     775        */
     776        public function isMail()
     777        {
     778                $this->Mailer = 'mail';
     779        }
    778780
    779     /**
    780     * Send messages using $Sendmail.
    781     * @return void
    782     */
    783     public function isSendmail()
    784     {
    785         $ini_sendmail_path = ini_get('sendmail_path');
     781        /**
     782        * Send messages using $Sendmail.
     783        * @return void
     784        */
     785        public function isSendmail()
     786        {
     787                $ini_sendmail_path = ini_get('sendmail_path');
    786788
    787         if (!stristr($ini_sendmail_path, 'sendmail')) {
    788             $this->Sendmail = '/usr/sbin/sendmail';
    789         } else {
    790             $this->Sendmail = $ini_sendmail_path;
    791         }
    792         $this->Mailer = 'sendmail';
    793     }
     789                if (!stristr($ini_sendmail_path, 'sendmail')) {
     790                        $this->Sendmail = '/usr/sbin/sendmail';
     791                } else {
     792                        $this->Sendmail = $ini_sendmail_path;
     793                }
     794                $this->Mailer = 'sendmail';
     795        }
    794796
    795     /**
    796     * Send messages using qmail.
    797     * @return void
    798     */
    799     public function isQmail()
    800     {
    801         $ini_sendmail_path = ini_get('sendmail_path');
     797        /**
     798        * Send messages using qmail.
     799        * @return void
     800        */
     801        public function isQmail()
     802        {
     803                $ini_sendmail_path = ini_get('sendmail_path');
    802804
    803         if (!stristr($ini_sendmail_path, 'qmail')) {
    804             $this->Sendmail = '/var/qmail/bin/qmail-inject';
    805         } else {
    806             $this->Sendmail = $ini_sendmail_path;
    807         }
    808         $this->Mailer = 'qmail';
    809     }
     805                if (!stristr($ini_sendmail_path, 'qmail')) {
     806                        $this->Sendmail = '/var/qmail/bin/qmail-inject';
     807                } else {
     808                        $this->Sendmail = $ini_sendmail_path;
     809                }
     810                $this->Mailer = 'qmail';
     811        }
    810812
    811     /**
    812     * Add a "To" address.
    813     * @param string $address The email address to send to
    814     * @param string $name
    815     * @return boolean true on success, false if address already used or invalid in some way
    816     */
    817     public function addAddress($address, $name = '')
    818     {
    819         return $this->addOrEnqueueAnAddress('to', $address, $name);
    820     }
     813        /**
     814        * Add a "To" address.
     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 addAddress($address, $name = '')
     820        {
     821                return $this->addOrEnqueueAnAddress('to', $address, $name);
     822        }
    821823
    822     /**
    823     * Add a "CC" address.
    824     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    825     * @param string $address The email address to send to
    826     * @param string $name
    827     * @return boolean true on success, false if address already used or invalid in some way
    828     */
    829     public function addCC($address, $name = '')
    830     {
    831         return $this->addOrEnqueueAnAddress('cc', $address, $name);
    832     }
     824        /**
     825        * Add a "CC" 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 addCC($address, $name = '')
     832        {
     833                return $this->addOrEnqueueAnAddress('cc', $address, $name);
     834        }
    833835
    834     /**
    835     * Add a "BCC" address.
    836     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    837     * @param string $address The email address to send to
    838     * @param string $name
    839     * @return boolean true on success, false if address already used or invalid in some way
    840     */
    841     public function addBCC($address, $name = '')
    842     {
    843         return $this->addOrEnqueueAnAddress('bcc', $address, $name);
    844     }
     836        /**
     837        * Add a "BCC" address.
     838        * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
     839        * @param string $address The email address to send to
     840        * @param string $name
     841        * @return boolean true on success, false if address already used or invalid in some way
     842        */
     843        public function addBCC($address, $name = '')
     844        {
     845                return $this->addOrEnqueueAnAddress('bcc', $address, $name);
     846        }
    845847
    846     /**
    847     * Add a "Reply-To" address.
    848     * @param string $address The email address to reply to
    849     * @param string $name
    850     * @return boolean true on success, false if address already used or invalid in some way
    851     */
    852     public function addReplyTo($address, $name = '')
    853     {
    854         return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
    855     }
     848        /**
     849        * Add a "Reply-To" address.
     850        * @param string $address The email address to reply to
     851        * @param string $name
     852        * @return boolean true on success, false if address already used or invalid in some way
     853        */
     854        public function addReplyTo($address, $name = '')
     855        {
     856                return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
     857        }
    856858
    857     /**
    858     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
    859     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
    860     * be modified after calling this function), addition of such addresses is delayed until send().
    861     * Addresses that have been added already return false, but do not throw exceptions.
    862     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
    863     * @param string $address The email address to send, resp. to reply to
    864     * @param string $name
    865     * @throws phpmailerException
    866     * @return boolean true on success, false if address already used or invalid in some way
    867     * @access protected
    868     */
    869     protected function addOrEnqueueAnAddress($kind, $address, $name)
    870     {
    871         $address = trim($address);
    872         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    873         if (($pos = strrpos($address, '@')) === false) {
    874             // At-sign is misssing.
    875             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
    876             $this->setError($error_message);
    877             $this->edebug($error_message);
    878             if ($this->exceptions) {
    879                 throw new phpmailerException($error_message);
    880             }
    881             return false;
    882         }
    883         $params = array($kind, $address, $name);
    884         // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
    885         if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
    886             if ($kind != 'Reply-To') {
    887                 if (!array_key_exists($address, $this->RecipientsQueue)) {
    888                     $this->RecipientsQueue[$address] = $params;
    889                     return true;
    890                 }
    891             } else {
    892                 if (!array_key_exists($address, $this->ReplyToQueue)) {
    893                     $this->ReplyToQueue[$address] = $params;
    894                     return true;
    895                 }
    896             }
    897             return false;
    898         }
    899         // Immediately add standard addresses without IDN.
    900         return call_user_func_array(array($this, 'addAnAddress'), $params);
    901     }
     859        /**
     860        * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
     861        * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
     862        * be modified after calling this function), addition of such addresses is delayed until send().
     863        * Addresses that have been added already return false, but do not throw exceptions.
     864        * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     865        * @param string $address The email address to send, resp. to reply to
     866        * @param string $name
     867        * @throws phpmailerException
     868        * @return boolean true on success, false if address already used or invalid in some way
     869        * @access protected
     870        */
     871        protected function addOrEnqueueAnAddress($kind, $address, $name)
     872        {
     873                $address = trim($address);
     874                $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     875                if (($pos = strrpos($address, '@')) === false) {
     876                        // At-sign is misssing.
     877                        $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     878                        $this->setError($error_message);
     879                        $this->edebug($error_message);
     880                        if ($this->exceptions) {
     881                                throw new phpmailerException($error_message);
     882                        }
     883                        return false;
     884                }
     885                $params = array($kind, $address, $name);
     886                // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
     887                if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
     888                        if ($kind != 'Reply-To') {
     889                                if (!array_key_exists($address, $this->RecipientsQueue)) {
     890                                        $this->RecipientsQueue[$address] = $params;
     891                                        return true;
     892                                }
     893                        } else {
     894                                if (!array_key_exists($address, $this->ReplyToQueue)) {
     895                                        $this->ReplyToQueue[$address] = $params;
     896                                        return true;
     897                                }
     898                        }
     899                        return false;
     900                }
     901                // Immediately add standard addresses without IDN.
     902                return call_user_func_array(array($this, 'addAnAddress'), $params);
     903        }
    902904
    903     /**
    904     * Add an address to one of the recipient arrays or to the ReplyTo array.
    905     * Addresses that have been added already return false, but do not throw exceptions.
    906     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
    907     * @param string $address The email address to send, resp. to reply to
    908     * @param string $name
    909     * @throws phpmailerException
    910     * @return boolean true on success, false if address already used or invalid in some way
    911     * @access protected
    912     */
    913     protected function addAnAddress($kind, $address, $name = '')
    914     {
    915         if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
    916             $error_message = $this->lang('Invalid recipient kind: ') . $kind;
    917             $this->setError($error_message);
    918             $this->edebug($error_message);
    919             if ($this->exceptions) {
    920                 throw new phpmailerException($error_message);
    921             }
    922             return false;
    923         }
    924         if (!$this->validateAddress($address)) {
    925             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
    926             $this->setError($error_message);
    927             $this->edebug($error_message);
    928             if ($this->exceptions) {
    929                 throw new phpmailerException($error_message);
    930             }
    931             return false;
    932         }
    933         if ($kind != 'Reply-To') {
    934             if (!array_key_exists(strtolower($address), $this->all_recipients)) {
    935                 array_push($this->$kind, array($address, $name));
    936                 $this->all_recipients[strtolower($address)] = true;
    937                 return true;
    938             }
    939         } else {
    940             if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
    941                 $this->ReplyTo[strtolower($address)] = array($address, $name);
    942                 return true;
    943             }
    944         }
    945         return false;
    946     }
     905        /**
     906        * Add an address to one of the recipient arrays or to the ReplyTo array.
     907        * Addresses that have been added already return false, but do not throw exceptions.
     908        * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     909        * @param string $address The email address to send, resp. to reply to
     910        * @param string $name
     911        * @throws phpmailerException
     912        * @return boolean true on success, false if address already used or invalid in some way
     913        * @access protected
     914        */
     915        protected function addAnAddress($kind, $address, $name = '')
     916        {
     917                if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
     918                        $error_message = $this->lang('Invalid recipient kind: ') . $kind;
     919                        $this->setError($error_message);
     920                        $this->edebug($error_message);
     921                        if ($this->exceptions) {
     922                                throw new phpmailerException($error_message);
     923                        }
     924                        return false;
     925                }
     926                if (!$this->validateAddress($address)) {
     927                        $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     928                        $this->setError($error_message);
     929                        $this->edebug($error_message);
     930                        if ($this->exceptions) {
     931                                throw new phpmailerException($error_message);
     932                        }
     933                        return false;
     934                }
     935                if ($kind != 'Reply-To') {
     936                        if (!array_key_exists(strtolower($address), $this->all_recipients)) {
     937                                array_push($this->$kind, array($address, $name));
     938                                $this->all_recipients[strtolower($address)] = true;
     939                                return true;
     940                        }
     941                } else {
     942                        if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
     943                                $this->ReplyTo[strtolower($address)] = array($address, $name);
     944                                return true;
     945                        }
     946                }
     947                return false;
     948        }
    947949
    948     /**
    949     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
    950     * of the form "display name <address>" into an array of name/address pairs.
    951     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
    952     * Note that quotes in the name part are removed.
    953     * @param string $addrstr The address list string
    954     * @param bool $useimap Whether to use the IMAP extension to parse the list
    955     * @return array
    956     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
    957     */
    958     public function parseAddresses($addrstr, $useimap = true)
    959     {
    960         $addresses = array();
    961         if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
    962             //Use this built-in parser if it's available
    963             $list = imap_rfc822_parse_adrlist($addrstr, '');
    964             foreach ($list as $address) {
    965                 if ($address->host != '.SYNTAX-ERROR.') {
    966                     if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
    967                         $addresses[] = array(
    968                             'name' => (property_exists($address, 'personal') ? $address->personal : ''),
    969                             'address' => $address->mailbox . '@' . $address->host
    970                         );
    971                     }
    972                 }
    973             }
    974         } else {
    975             //Use this simpler parser
    976             $list = explode(',', $addrstr);
    977             foreach ($list as $address) {
    978                 $address = trim($address);
    979                 //Is there a separate name part?
    980                 if (strpos($address, '<') === false) {
    981                     //No separate name, just use the whole thing
    982                     if ($this->validateAddress($address)) {
    983                         $addresses[] = array(
    984                             'name' => '',
    985                             'address' => $address
    986                         );
    987                     }
    988                 } else {
    989                     list($name, $email) = explode('<', $address);
    990                     $email = trim(str_replace('>', '', $email));
    991                     if ($this->validateAddress($email)) {
    992                         $addresses[] = array(
    993                             'name' => trim(str_replace(array('"', "'"), '', $name)),
    994                             'address' => $email
    995                         );
    996                     }
    997                 }
    998             }
    999         }
    1000         return $addresses;
    1001     }
     950        /**
     951        * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
     952        * of the form "display name <address>" into an array of name/address pairs.
     953        * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
     954        * Note that quotes in the name part are removed.
     955        * @param string $addrstr The address list string
     956        * @param bool $useimap Whether to use the IMAP extension to parse the list
     957        * @return array
     958        * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
     959        */
     960        public function parseAddresses($addrstr, $useimap = true)
     961        {
     962                $addresses = array();
     963                if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
     964                        //Use this built-in parser if it's available
     965                        $list = imap_rfc822_parse_adrlist($addrstr, '');
     966                        foreach ($list as $address) {
     967                                if ($address->host != '.SYNTAX-ERROR.') {
     968                                        if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
     969                                                $addresses[] = array(
     970                                                        'name' => (property_exists($address, 'personal') ? $address->personal : ''),
     971                                                        'address' => $address->mailbox . '@' . $address->host
     972                                                );
     973                                        }
     974                                }
     975                        }
     976                } else {
     977                        //Use this simpler parser
     978                        $list = explode(',', $addrstr);
     979                        foreach ($list as $address) {
     980                                $address = trim($address);
     981                                //Is there a separate name part?
     982                                if (strpos($address, '<') === false) {
     983                                        //No separate name, just use the whole thing
     984                                        if ($this->validateAddress($address)) {
     985                                                $addresses[] = array(
     986                                                        'name' => '',
     987                                                        'address' => $address
     988                                                );
     989                                        }
     990                                } else {
     991                                        list($name, $email) = explode('<', $address);
     992                                        $email = trim(str_replace('>', '', $email));
     993                                        if ($this->validateAddress($email)) {
     994                                                $addresses[] = array(
     995                                                        'name' => trim(str_replace(array('"', "'"), '', $name)),
     996                                                        'address' => $email
     997                                                );
     998                                        }
     999                                }
     1000                        }
     1001                }
     1002                return $addresses;
     1003        }
    10021004
    1003     /**
    1004     * Set the From and FromName properties.
    1005     * @param string $address
    1006     * @param string $name
    1007     * @param boolean $auto Whether to also set the Sender address, defaults to true
    1008     * @throws phpmailerException
    1009     * @return boolean
    1010     */
    1011     public function setFrom($address, $name = '', $auto = true)
    1012     {
    1013         $address = trim($address);
    1014         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    1015         // Don't validate now addresses with IDN. Will be done in send().
    1016         if (($pos = strrpos($address, '@')) === false or
    1017             (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
    1018             !$this->validateAddress($address)) {
    1019             $error_message = $this->lang('invalid_address') . " (setFrom) $address";
    1020             $this->setError($error_message);
    1021             $this->edebug($error_message);
    1022             if ($this->exceptions) {
    1023                 throw new phpmailerException($error_message);
    1024             }
    1025             return false;
    1026         }
    1027         $this->From = $address;
    1028         $this->FromName = $name;
    1029         if ($auto) {
    1030             if (empty($this->Sender)) {
    1031                 $this->Sender = $address;
    1032             }
    1033         }
    1034         return true;
    1035     }
     1005        /**
     1006        * Set the From and FromName properties.
     1007        * @param string $address
     1008        * @param string $name
     1009        * @param boolean $auto Whether to also set the Sender address, defaults to true
     1010        * @throws phpmailerException
     1011        * @return boolean
     1012        */
     1013        public function setFrom($address, $name = '', $auto = true)
     1014        {
     1015                $address = trim($address);
     1016                $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     1017                // Don't validate now addresses with IDN. Will be done in send().
     1018                if (($pos = strrpos($address, '@')) === false or
     1019                        (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
     1020                        !$this->validateAddress($address)) {
     1021                        $error_message = $this->lang('invalid_address') . " (setFrom) $address";
     1022                        $this->setError($error_message);
     1023                        $this->edebug($error_message);
     1024                        if ($this->exceptions) {
     1025                                throw new phpmailerException($error_message);
     1026                        }
     1027                        return false;
     1028                }
     1029                $this->From = $address;
     1030                $this->FromName = $name;
     1031                if ($auto) {
     1032                        if (empty($this->Sender)) {
     1033                                $this->Sender = $address;
     1034                        }
     1035                }
     1036                return true;
     1037        }
    10361038
    1037     /**
    1038     * Return the Message-ID header of the last email.
    1039     * Technically this is the value from the last time the headers were created,
    1040     * but it's also the message ID of the last sent message except in
    1041     * pathological cases.
    1042     * @return string
    1043     */
    1044     public function getLastMessageID()
    1045     {
    1046         return $this->lastMessageID;
    1047     }
     1039        /**
     1040        * Return the Message-ID header of the last email.
     1041        * Technically this is the value from the last time the headers were created,
     1042        * but it's also the message ID of the last sent message except in
     1043        * pathological cases.
     1044        * @return string
     1045        */
     1046        public function getLastMessageID()
     1047        {
     1048                return $this->lastMessageID;
     1049        }
    10481050
    1049     /**
    1050     * Check that a string looks like an email address.
    1051     * @param string $address The email address to check
    1052     * @param string|callable $patternselect A selector for the validation pattern to use :
    1053     * * `auto` Pick best pattern automatically;
    1054     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
    1055     * * `pcre` Use old PCRE implementation;
    1056     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
    1057     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
    1058     * * `noregex` Don't use a regex: super fast, really dumb.
    1059     * Alternatively you may pass in a callable to inject your own validator, for example:
    1060     * PHPMailer::validateAddress('user@example.com', function($address) {
    1061      *    return (strpos($address, '@') !== false);
    1062     * });
    1063     * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
    1064     * @return boolean
    1065     * @static
    1066     * @access public
    1067     */
    1068     public static function validateAddress($address, $patternselect = null)
    1069     {
    1070         if (is_null($patternselect)) {
    1071             $patternselect = self::$validator;
    1072         }
    1073         if (is_callable($patternselect)) {
    1074             return call_user_func($patternselect, $address);
    1075         }
    1076         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
    1077         if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
    1078             return false;
    1079         }
    1080         if (!$patternselect or $patternselect == 'auto') {
    1081             //Check this constant first so it works when extension_loaded() is disabled by safe mode
    1082             //Constant was added in PHP 5.2.4
    1083             if (defined('PCRE_VERSION')) {
    1084                 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
    1085                 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
    1086                     $patternselect = 'pcre8';
    1087                 } else {
    1088                     $patternselect = 'pcre';
    1089                 }
    1090             } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
    1091                 //Fall back to older PCRE
    1092                 $patternselect = 'pcre';
    1093             } else {
    1094                 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
    1095                 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
    1096                     $patternselect = 'php';
    1097                 } else {
    1098                     $patternselect = 'noregex';
    1099                 }
    1100             }
    1101         }
    1102         switch ($patternselect) {
    1103             case 'pcre8':
    1104                 /**
    1105                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
    1106                 * @link http://squiloople.com/2009/12/20/email-address-validation/
    1107                 * @copyright 2009-2010 Michael Rushton
    1108                 * Feel free to use and redistribute this code. But please keep this copyright notice.
    1109                 */
    1110                 return (boolean)preg_match(
    1111                     '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
    1112                     '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
    1113                     '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
    1114                     '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
    1115                     '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
    1116                     '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
    1117                     '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
    1118                     '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
    1119                     '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
    1120                     $address
    1121                 );
    1122             case 'pcre':
    1123                 //An older regex that doesn't need a recent PCRE
    1124                 return (boolean)preg_match(
    1125                     '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
    1126                     '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
    1127                     '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
    1128                     '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
    1129                     '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
    1130                     '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
    1131                     '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
    1132                     '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
    1133                     '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
    1134                     '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
    1135                     $address
    1136                 );
    1137             case 'html5':
    1138                 /**
    1139                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
    1140                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
    1141                 */
    1142                 return (boolean)preg_match(
    1143                     '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
    1144                     '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
    1145                     $address
    1146                 );
    1147             case 'noregex':
    1148                 //No PCRE! Do something _very_ approximate!
    1149                 //Check the address is 3 chars or longer and contains an @ that's not the first or last char
    1150                 return (strlen($address) >= 3
    1151                     and strpos($address, '@') >= 1
    1152                     and strpos($address, '@') != strlen($address) - 1);
    1153             case 'php':
    1154             default:
    1155                 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
    1156         }
    1157     }
     1051        /**
     1052        * Check that a string looks like an email address.
     1053        * @param string $address The email address to check
     1054        * @param string|callable $patternselect A selector for the validation pattern to use :
     1055        * * `auto` Pick best pattern automatically;
     1056        * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
     1057        * * `pcre` Use old PCRE implementation;
     1058        * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
     1059        * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
     1060        * * `noregex` Don't use a regex: super fast, really dumb.
     1061        * Alternatively you may pass in a callable to inject your own validator, for example:
     1062        * PHPMailer::validateAddress('user@example.com', function($address) {
     1063         *      return (strpos($address, '@') !== false);
     1064        * });
     1065        * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
     1066        * @return boolean
     1067        * @static
     1068        * @access public
     1069        */
     1070        public static function validateAddress($address, $patternselect = null)
     1071        {
     1072                if (is_null($patternselect)) {
     1073                        $patternselect = self::$validator;
     1074                }
     1075                if (is_callable($patternselect)) {
     1076                        return call_user_func($patternselect, $address);
     1077                }
     1078                //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
     1079                if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
     1080                        return false;
     1081                }
     1082                if (!$patternselect or $patternselect == 'auto') {
     1083                        //Check this constant first so it works when extension_loaded() is disabled by safe mode
     1084                        //Constant was added in PHP 5.2.4
     1085                        if (defined('PCRE_VERSION')) {
     1086                                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
     1087                                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
     1088                                        $patternselect = 'pcre8';
     1089                                } else {
     1090                                        $patternselect = 'pcre';
     1091                                }
     1092                        } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
     1093                                //Fall back to older PCRE
     1094                                $patternselect = 'pcre';
     1095                        } else {
     1096                                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
     1097                                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
     1098                                        $patternselect = 'php';
     1099                                } else {
     1100                                        $patternselect = 'noregex';
     1101                                }
     1102                        }
     1103                }
     1104                switch ($patternselect) {
     1105                        case 'pcre8':
     1106                                /**
     1107                                * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
     1108                                * @link http://squiloople.com/2009/12/20/email-address-validation/
     1109                                * @copyright 2009-2010 Michael Rushton
     1110                                * Feel free to use and redistribute this code. But please keep this copyright notice.
     1111                                */
     1112                                return (boolean)preg_match(
     1113                                        '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
     1114                                        '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
     1115                                        '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
     1116                                        '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
     1117                                        '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
     1118                                        '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
     1119                                        '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
     1120                                        '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
     1121                                        '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
     1122                                        $address
     1123                                );
     1124                        case 'pcre':
     1125                                //An older regex that doesn't need a recent PCRE
     1126                                return (boolean)preg_match(
     1127                                        '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
     1128                                        '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
     1129                                        '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
     1130                                        '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
     1131                                        '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
     1132                                        '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
     1133                                        '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
     1134                                        '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
     1135                                        '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
     1136                                        '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
     1137                                        $address
     1138                                );
     1139                        case 'html5':
     1140                                /**
     1141                                * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
     1142                                * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
     1143                                */
     1144                                return (boolean)preg_match(
     1145                                        '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
     1146                                        '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
     1147                                        $address
     1148                                );
     1149                        case 'noregex':
     1150                                //No PCRE! Do something _very_ approximate!
     1151                                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
     1152                                return (strlen($address) >= 3
     1153                                        and strpos($address, '@') >= 1
     1154                                        and strpos($address, '@') != strlen($address) - 1);
     1155                        case 'php':
     1156                        default:
     1157                                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
     1158                }
     1159        }
    11581160
    1159     /**
    1160     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
    1161     * "intl" and "mbstring" PHP extensions.
    1162     * @return bool "true" if required functions for IDN support are present
    1163     */
    1164     public function idnSupported()
    1165     {
    1166         // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
    1167         return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
    1168     }
     1161        /**
     1162        * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
     1163        * "intl" and "mbstring" PHP extensions.
     1164        * @return bool "true" if required functions for IDN support are present
     1165        */
     1166        public function idnSupported()
     1167        {
     1168                // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
     1169                return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
     1170        }
    11691171
    1170     /**
    1171     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
    1172     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
    1173     * This function silently returns unmodified address if:
    1174     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
    1175     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
    1176     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
    1177     * @see PHPMailer::$CharSet
    1178     * @param string $address The email address to convert
    1179     * @return string The encoded address in ASCII form
    1180     */
    1181     public function punyencodeAddress($address)
    1182     {
    1183         // Verify we have required functions, CharSet, and at-sign.
    1184         if ($this->idnSupported() and
    1185             !empty($this->CharSet) and
    1186             ($pos = strrpos($address, '@')) !== false) {
    1187             $domain = substr($address, ++$pos);
    1188             // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
    1189             if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
    1190                 $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
    1191                 if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
    1192                     idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
    1193                     idn_to_ascii($domain)) !== false) {
    1194                     return substr($address, 0, $pos) . $punycode;
    1195                 }
    1196             }
    1197         }
    1198         return $address;
    1199     }
     1172        /**
     1173        * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
     1174        * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
     1175        * This function silently returns unmodified address if:
     1176        * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
     1177        * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
     1178        *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
     1179        * @see PHPMailer::$CharSet
     1180        * @param string $address The email address to convert
     1181        * @return string The encoded address in ASCII form
     1182        */
     1183        public function punyencodeAddress($address)
     1184        {
     1185                // Verify we have required functions, CharSet, and at-sign.
     1186                if ($this->idnSupported() and
     1187                        !empty($this->CharSet) and
     1188                        ($pos = strrpos($address, '@')) !== false) {
     1189                        $domain = substr($address, ++$pos);
     1190                        // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
     1191                        if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
     1192                                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
     1193                                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
     1194                                        idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
     1195                                        idn_to_ascii($domain)) !== false) {
     1196                                        return substr($address, 0, $pos) . $punycode;
     1197                                }
     1198                        }
     1199                }
     1200                return $address;
     1201        }
    12001202
    1201     /**
    1202     * Create a message and send it.
    1203     * Uses the sending method specified by $Mailer.
    1204     * @throws phpmailerException
    1205     * @return boolean false on error - See the ErrorInfo property for details of the error.
    1206     */
    1207     public function send()
    1208     {
    1209         try {
    1210             if (!$this->preSend()) {
    1211                 return false;
    1212             }
    1213             return $this->postSend();
    1214         } catch (phpmailerException $exc) {
    1215             $this->mailHeader = '';
    1216             $this->setError($exc->getMessage());
    1217             if ($this->exceptions) {
    1218                 throw $exc;
    1219             }
    1220             return false;
    1221         }
    1222     }
     1203        /**
     1204        * Create a message and send it.
     1205        * Uses the sending method specified by $Mailer.
     1206        * @throws phpmailerException
     1207        * @return boolean false on error - See the ErrorInfo property for details of the error.
     1208        */
     1209        public function send()
     1210        {
     1211                try {
     1212                        if (!$this->preSend()) {
     1213                                return false;
     1214                        }
     1215                        return $this->postSend();
     1216                } catch (phpmailerException $exc) {
     1217                        $this->mailHeader = '';
     1218                        $this->setError($exc->getMessage());
     1219                        if ($this->exceptions) {
     1220                                throw $exc;
     1221                        }
     1222                        return false;
     1223                }
     1224        }
    12231225
    1224     /**
    1225     * Prepare a message for sending.
    1226     * @throws phpmailerException
    1227     * @return boolean
    1228     */
    1229     public function preSend()
    1230     {
    1231         try {
    1232             $this->error_count = 0; // Reset errors
    1233             $this->mailHeader = '';
     1226        /**
     1227        * Prepare a message for sending.
     1228        * @throws phpmailerException
     1229        * @return boolean
     1230        */
     1231        public function preSend()
     1232        {
     1233                try {
     1234                        $this->error_count = 0; // Reset errors
     1235                        $this->mailHeader = '';
    12341236
    1235             // Dequeue recipient and Reply-To addresses with IDN
    1236             foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
    1237                 $params[1] = $this->punyencodeAddress($params[1]);
    1238                 call_user_func_array(array($this, 'addAnAddress'), $params);
    1239             }
    1240             if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
    1241                 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
    1242             }
     1237                        // Dequeue recipient and Reply-To addresses with IDN
     1238                        foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
     1239                                $params[1] = $this->punyencodeAddress($params[1]);
     1240                                call_user_func_array(array($this, 'addAnAddress'), $params);
     1241                        }
     1242                        if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
     1243                                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
     1244                        }
    12431245
    1244             // Validate From, Sender, and ConfirmReadingTo addresses
    1245             foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
    1246                 $this->$address_kind = trim($this->$address_kind);
    1247                 if (empty($this->$address_kind)) {
    1248                     continue;
    1249                 }
    1250                 $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
    1251                 if (!$this->validateAddress($this->$address_kind)) {
    1252                     $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
    1253                     $this->setError($error_message);
    1254                     $this->edebug($error_message);
    1255                     if ($this->exceptions) {
    1256                         throw new phpmailerException($error_message);
    1257                     }
    1258                     return false;
    1259                 }
    1260             }
     1246                        // Validate From, Sender, and ConfirmReadingTo addresses
     1247                        foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
     1248                                $this->$address_kind = trim($this->$address_kind);
     1249                                if (empty($this->$address_kind)) {
     1250                                        continue;
     1251                                }
     1252                                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
     1253                                if (!$this->validateAddress($this->$address_kind)) {
     1254                                        $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
     1255                                        $this->setError($error_message);
     1256                                        $this->edebug($error_message);
     1257                                        if ($this->exceptions) {
     1258                                                throw new phpmailerException($error_message);
     1259                                        }
     1260                                        return false;
     1261                                }
     1262                        }
    12611263
    1262             // Set whether the message is multipart/alternative
    1263             if ($this->alternativeExists()) {
    1264                 $this->ContentType = 'multipart/alternative';
    1265             }
     1264                        // Set whether the message is multipart/alternative
     1265                        if ($this->alternativeExists()) {
     1266                                $this->ContentType = 'multipart/alternative';
     1267                        }
    12661268
    1267             $this->setMessageType();
    1268             // Refuse to send an empty message unless we are specifically allowing it
    1269             if (!$this->AllowEmpty and empty($this->Body)) {
    1270                 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
    1271             }
     1269                        $this->setMessageType();
     1270                        // Refuse to send an empty message unless we are specifically allowing it
     1271                        if (!$this->AllowEmpty and empty($this->Body)) {
     1272                                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
     1273                        }
    12721274
    1273             // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
    1274             $this->MIMEHeader = '';
    1275             $this->MIMEBody = $this->createBody();
    1276             // createBody may have added some headers, so retain them
    1277             $tempheaders = $this->MIMEHeader;
    1278             $this->MIMEHeader = $this->createHeader();
    1279             $this->MIMEHeader .= $tempheaders;
     1275                        // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
     1276                        $this->MIMEHeader = '';
     1277                        $this->MIMEBody = $this->createBody();
     1278                        // createBody may have added some headers, so retain them
     1279                        $tempheaders = $this->MIMEHeader;
     1280                        $this->MIMEHeader = $this->createHeader();
     1281                        $this->MIMEHeader .= $tempheaders;
    12801282
    1281             // To capture the complete message when using mail(), create
    1282             // an extra header list which createHeader() doesn't fold in
    1283             if ($this->Mailer == 'mail') {
    1284                 if (count($this->to) > 0) {
    1285                     $this->mailHeader .= $this->addrAppend('To', $this->to);
    1286                 } else {
    1287                     $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
    1288                 }
    1289                 $this->mailHeader .= $this->headerLine(
    1290                     'Subject',
    1291                     $this->encodeHeader($this->secureHeader(trim($this->Subject)))
    1292                 );
    1293             }
     1283                        // To capture the complete message when using mail(), create
     1284                        // an extra header list which createHeader() doesn't fold in
     1285                        if ($this->Mailer == 'mail') {
     1286                                if (count($this->to) > 0) {
     1287                                        $this->mailHeader .= $this->addrAppend('To', $this->to);
     1288                                } else {
     1289                                        $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
     1290                                }
     1291                                $this->mailHeader .= $this->headerLine(
     1292                                        'Subject',
     1293                                        $this->encodeHeader($this->secureHeader(trim($this->Subject)))
     1294                                );
     1295                        }
    12941296
    1295             // Sign with DKIM if enabled
    1296             if (!empty($this->DKIM_domain)
    1297                 && !empty($this->DKIM_selector)
    1298                 && (!empty($this->DKIM_private_string)
    1299                    || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
    1300                 )
    1301             ) {
    1302                 $header_dkim = $this->DKIM_Add(
    1303                     $this->MIMEHeader . $this->mailHeader,
    1304                     $this->encodeHeader($this->secureHeader($this->Subject)),
    1305                     $this->MIMEBody
    1306                 );
    1307                 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
    1308                     str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
    1309             }
    1310             return true;
    1311         } catch (phpmailerException $exc) {
    1312             $this->setError($exc->getMessage());
    1313             if ($this->exceptions) {
    1314                 throw $exc;
    1315             }
    1316             return false;
    1317         }
    1318     }
     1297                        // Sign with DKIM if enabled
     1298                        if (!empty($this->DKIM_domain)
     1299                                && !empty($this->DKIM_selector)
     1300                                && (!empty($this->DKIM_private_string)
     1301                                   || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
     1302                                )
     1303                        ) {
     1304                                $header_dkim = $this->DKIM_Add(
     1305                                        $this->MIMEHeader . $this->mailHeader,
     1306                                        $this->encodeHeader($this->secureHeader($this->Subject)),
     1307                                        $this->MIMEBody
     1308                                );
     1309                                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
     1310                                        str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
     1311                        }
     1312                        return true;
     1313                } catch (phpmailerException $exc) {
     1314                        $this->setError($exc->getMessage());
     1315                        if ($this->exceptions) {
     1316                                throw $exc;
     1317                        }
     1318                        return false;
     1319                }
     1320        }
    13191321
    1320     /**
    1321     * Actually send a message.
    1322     * Send the email via the selected mechanism
    1323     * @throws phpmailerException
    1324     * @return boolean
    1325     */
    1326     public function postSend()
    1327     {
    1328         try {
    1329             // Choose the mailer and send through it
    1330             switch ($this->Mailer) {
    1331                 case 'sendmail':
    1332                 case 'qmail':
    1333                     return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
    1334                 case 'smtp':
    1335                     return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
    1336                 case 'mail':
    1337                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
    1338                 default:
    1339                     $sendMethod = $this->Mailer.'Send';
    1340                     if (method_exists($this, $sendMethod)) {
    1341                         return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
    1342                     }
     1322        /**
     1323        * Actually send a message.
     1324        * Send the email via the selected mechanism
     1325        * @throws phpmailerException
     1326        * @return boolean
     1327        */
     1328        public function postSend()
     1329        {
     1330                try {
     1331                        // Choose the mailer and send through it
     1332                        switch ($this->Mailer) {
     1333                                case 'sendmail':
     1334                                case 'qmail':
     1335                                        return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
     1336                                case 'smtp':
     1337                                        return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
     1338                                case 'mail':
     1339                                        return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
     1340                                default:
     1341                                        $sendMethod = $this->Mailer.'Send';
     1342                                        if (method_exists($this, $sendMethod)) {
     1343                                                return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
     1344                                        }
    13431345
    1344                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
    1345             }
    1346         } catch (phpmailerException $exc) {
    1347             $this->setError($exc->getMessage());
    1348             $this->edebug($exc->getMessage());
    1349             if ($this->exceptions) {
    1350                 throw $exc;
    1351             }
    1352         }
    1353         return false;
    1354     }
     1346                                        return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
     1347                        }
     1348                } catch (phpmailerException $exc) {
     1349                        $this->setError($exc->getMessage());
     1350                        $this->edebug($exc->getMessage());
     1351                        if ($this->exceptions) {
     1352                                throw $exc;
     1353                        }
     1354                }
     1355                return false;
     1356        }
    13551357
    1356     /**
    1357     * Send mail using the $Sendmail program.
    1358     * @param string $header The message headers
    1359     * @param string $body The message body
    1360     * @see PHPMailer::$Sendmail
    1361     * @throws phpmailerException
    1362     * @access protected
    1363     * @return boolean
    1364     */
    1365     protected function sendmailSend($header, $body)
    1366     {
    1367         // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1368         if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
    1369             if ($this->Mailer == 'qmail') {
    1370                 $sendmailFmt = '%s -f%s';
    1371             } else {
    1372                 $sendmailFmt = '%s -oi -f%s -t';
    1373             }
    1374         } else {
    1375             if ($this->Mailer == 'qmail') {
    1376                 $sendmailFmt = '%s';
    1377             } else {
    1378                 $sendmailFmt = '%s -oi -t';
    1379             }
    1380         }
     1358        /**
     1359        * Send mail using the $Sendmail program.
     1360        * @param string $header The message headers
     1361        * @param string $body The message body
     1362        * @see PHPMailer::$Sendmail
     1363        * @throws phpmailerException
     1364        * @access protected
     1365        * @return boolean
     1366        */
     1367        protected function sendmailSend($header, $body)
     1368        {
     1369                // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1370                if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
     1371                        if ($this->Mailer == 'qmail') {
     1372                                $sendmailFmt = '%s -f%s';
     1373                        } else {
     1374                                $sendmailFmt = '%s -oi -f%s -t';
     1375                        }
     1376                } else {
     1377                        if ($this->Mailer == 'qmail') {
     1378                                $sendmailFmt = '%s';
     1379                        } else {
     1380                                $sendmailFmt = '%s -oi -t';
     1381                        }
     1382                }
    13811383
    1382         // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
    1383         $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
     1384                // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
     1385                $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
    13841386
    1385         if ($this->SingleTo) {
    1386             foreach ($this->SingleToArray as $toAddr) {
    1387                 if (!@$mail = popen($sendmail, 'w')) {
    1388                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1389                 }
    1390                 fputs($mail, 'To: ' . $toAddr . "\n");
    1391                 fputs($mail, $header);
    1392                 fputs($mail, $body);
    1393                 $result = pclose($mail);
    1394                 $this->doCallback(
    1395                     ($result == 0),
    1396                     array($toAddr),
    1397                     $this->cc,
    1398                     $this->bcc,
    1399                     $this->Subject,
    1400                     $body,
    1401                     $this->From
    1402                 );
    1403                 if ($result != 0) {
    1404                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1405                 }
    1406             }
    1407         } else {
    1408             if (!@$mail = popen($sendmail, 'w')) {
    1409                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1410             }
    1411             fputs($mail, $header);
    1412             fputs($mail, $body);
    1413             $result = pclose($mail);
    1414             $this->doCallback(
    1415                 ($result == 0),
    1416                 $this->to,
    1417                 $this->cc,
    1418                 $this->bcc,
    1419                 $this->Subject,
    1420                 $body,
    1421                 $this->From
    1422             );
    1423             if ($result != 0) {
    1424                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1425             }
    1426         }
    1427         return true;
    1428     }
     1387                if ($this->SingleTo) {
     1388                        foreach ($this->SingleToArray as $toAddr) {
     1389                                if (!@$mail = popen($sendmail, 'w')) {
     1390                                        throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1391                                }
     1392                                fputs($mail, 'To: ' . $toAddr . "\n");
     1393                                fputs($mail, $header);
     1394                                fputs($mail, $body);
     1395                                $result = pclose($mail);
     1396                                $this->doCallback(
     1397                                        ($result == 0),
     1398                                        array($toAddr),
     1399                                        $this->cc,
     1400                                        $this->bcc,
     1401                                        $this->Subject,
     1402                                        $body,
     1403                                        $this->From
     1404                                );
     1405                                if ($result != 0) {
     1406                                        throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1407                                }
     1408                        }
     1409                } else {
     1410                        if (!@$mail = popen($sendmail, 'w')) {
     1411                                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1412                        }
     1413                        fputs($mail, $header);
     1414                        fputs($mail, $body);
     1415                        $result = pclose($mail);
     1416                        $this->doCallback(
     1417                                ($result == 0),
     1418                                $this->to,
     1419                                $this->cc,
     1420                                $this->bcc,
     1421                                $this->Subject,
     1422                                $body,
     1423                                $this->From
     1424                        );
     1425                        if ($result != 0) {
     1426                                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1427                        }
     1428                }
     1429                return true;
     1430        }
    14291431
    1430     /**
    1431     * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
    1432     *
    1433     * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
    1434     * @param string $string The string to be validated
    1435     * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
    1436     * @access protected
    1437     * @return boolean
    1438     */
    1439     protected static function isShellSafe($string)
    1440     {
    1441         // Future-proof
    1442         if (escapeshellcmd($string) !== $string
    1443             or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
    1444         ) {
    1445             return false;
    1446         }
     1432        /**
     1433        * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
     1434        *
     1435        * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
     1436        * @param string $string The string to be validated
     1437        * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
     1438        * @access protected
     1439        * @return boolean
     1440        */
     1441        protected static function isShellSafe($string)
     1442        {
     1443                // Future-proof
     1444                if (escapeshellcmd($string) !== $string
     1445                        or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
     1446                ) {
     1447                        return false;
     1448                }
    14471449
    1448         $length = strlen($string);
     1450                $length = strlen($string);
    14491451
    1450         for ($i = 0; $i < $length; $i++) {
    1451             $c = $string[$i];
     1452                for ($i = 0; $i < $length; $i++) {
     1453                        $c = $string[$i];
    14521454
    1453             // All other characters have a special meaning in at least one common shell, including = and +.
    1454             // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
    1455             // Note that this does permit non-Latin alphanumeric characters based on the current locale.
    1456             if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
    1457                 return false;
    1458             }
    1459         }
     1455                        // All other characters have a special meaning in at least one common shell, including = and +.
     1456                        // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
     1457                        // Note that this does permit non-Latin alphanumeric characters based on the current locale.
     1458                        if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
     1459                                return false;
     1460                        }
     1461                }
    14601462
    1461         return true;
    1462     }
     1463                return true;
     1464        }
    14631465
    1464     /**
    1465     * Send mail using the PHP mail() function.
    1466     * @param string $header The message headers
    1467     * @param string $body The message body
    1468     * @link http://www.php.net/manual/en/book.mail.php
    1469     * @throws phpmailerException
    1470     * @access protected
    1471     * @return boolean
    1472     */
    1473     protected function mailSend($header, $body)
    1474     {
    1475         $toArr = array();
    1476         foreach ($this->to as $toaddr) {
    1477             $toArr[] = $this->addrFormat($toaddr);
    1478         }
    1479         $to = implode(', ', $toArr);
     1466        /**
     1467        * Send mail using the PHP mail() function.
     1468        * @param string $header The message headers
     1469        * @param string $body The message body
     1470        * @link http://www.php.net/manual/en/book.mail.php
     1471        * @throws phpmailerException
     1472        * @access protected
     1473        * @return boolean
     1474        */
     1475        protected function mailSend($header, $body)
     1476        {
     1477                $toArr = array();
     1478                foreach ($this->to as $toaddr) {
     1479                        $toArr[] = $this->addrFormat($toaddr);
     1480                }
     1481                $to = implode(', ', $toArr);
    14801482
    1481         $params = null;
    1482         //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
    1483         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
    1484             // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1485             if (self::isShellSafe($this->Sender)) {
    1486                 $params = sprintf('-f%s', $this->Sender);
    1487             }
    1488         }
    1489         if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
    1490             $old_from = ini_get('sendmail_from');
    1491             ini_set('sendmail_from', $this->Sender);
    1492         }
    1493         $result = false;
    1494         if ($this->SingleTo and count($toArr) > 1) {
    1495             foreach ($toArr as $toAddr) {
    1496                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
    1497                 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
    1498             }
    1499         } else {
    1500             $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
    1501             $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
    1502         }
    1503         if (isset($old_from)) {
    1504             ini_set('sendmail_from', $old_from);
    1505         }
    1506         if (!$result) {
    1507             throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
    1508         }
    1509         return true;
    1510     }
     1483                $params = null;
     1484                //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
     1485                if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1486                        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1487                        if (self::isShellSafe($this->Sender)) {
     1488                                $params = sprintf('-f%s', $this->Sender);
     1489                        }
     1490                }
     1491                if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
     1492                        $old_from = ini_get('sendmail_from');
     1493                        ini_set('sendmail_from', $this->Sender);
     1494                }
     1495                $result = false;
     1496                if ($this->SingleTo and count($toArr) > 1) {
     1497                        foreach ($toArr as $toAddr) {
     1498                                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
     1499                                $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1500                        }
     1501                } else {
     1502                        $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
     1503                        $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1504                }
     1505                if (isset($old_from)) {
     1506                        ini_set('sendmail_from', $old_from);
     1507                }
     1508                if (!$result) {
     1509                        throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
     1510                }
     1511                return true;
     1512        }
    15111513
    1512     /**
    1513     * Get an instance to use for SMTP operations.
    1514     * Override this function to load your own SMTP implementation
    1515     * @return SMTP
    1516     */
    1517     public function getSMTPInstance()
    1518     {
    1519         if (!is_object($this->smtp)) {
     1514        /**
     1515        * Get an instance to use for SMTP operations.
     1516        * Override this function to load your own SMTP implementation
     1517        * @return SMTP
     1518        */
     1519        public function getSMTPInstance()
     1520        {
     1521                if (!is_object($this->smtp)) {
    15201522                        require_once( 'class-smtp.php' );
    1521             $this->smtp = new SMTP;
    1522         }
    1523         return $this->smtp;
    1524     }
     1523                        $this->smtp = new SMTP;
     1524                }
     1525                return $this->smtp;
     1526        }
    15251527
    1526     /**
    1527     * Send mail via SMTP.
    1528     * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
    1529     * Uses the PHPMailerSMTP class by default.
    1530     * @see PHPMailer::getSMTPInstance() to use a different class.
    1531     * @param string $header The message headers
    1532     * @param string $body The message body
    1533     * @throws phpmailerException
    1534     * @uses SMTP
    1535     * @access protected
    1536     * @return boolean
    1537     */
    1538     protected function smtpSend($header, $body)
    1539     {
    1540         $bad_rcpt = array();
    1541         if (!$this->smtpConnect($this->SMTPOptions)) {
    1542             throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
    1543         }
    1544         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
    1545             $smtp_from = $this->Sender;
    1546         } else {
    1547             $smtp_from = $this->From;
    1548         }
    1549         if (!$this->smtp->mail($smtp_from)) {
    1550             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
    1551             throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
    1552         }
     1528        /**
     1529        * Send mail via SMTP.
     1530        * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
     1531        * Uses the PHPMailerSMTP class by default.
     1532        * @see PHPMailer::getSMTPInstance() to use a different class.
     1533        * @param string $header The message headers
     1534        * @param string $body The message body
     1535        * @throws phpmailerException
     1536        * @uses SMTP
     1537        * @access protected
     1538        * @return boolean
     1539        */
     1540        protected function smtpSend($header, $body)
     1541        {
     1542                $bad_rcpt = array();
     1543                if (!$this->smtpConnect($this->SMTPOptions)) {
     1544                        throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
     1545                }
     1546                if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1547                        $smtp_from = $this->Sender;
     1548                } else {
     1549                        $smtp_from = $this->From;
     1550                }
     1551                if (!$this->smtp->mail($smtp_from)) {
     1552                        $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
     1553                        throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
     1554                }
    15531555
    1554         // Attempt to send to all recipients
    1555         foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
    1556             foreach ($togroup as $to) {
    1557                 if (!$this->smtp->recipient($to[0])) {
    1558                     $error = $this->smtp->getError();
    1559                     $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
    1560                     $isSent = false;
    1561                 } else {
    1562                     $isSent = true;
    1563                 }
    1564                 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
    1565             }
    1566         }
     1556                // Attempt to send to all recipients
     1557                foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
     1558                        foreach ($togroup as $to) {
     1559                                if (!$this->smtp->recipient($to[0])) {
     1560                                        $error = $this->smtp->getError();
     1561                                        $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
     1562                                        $isSent = false;
     1563                                } else {
     1564                                        $isSent = true;
     1565                                }
     1566                                $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
     1567                        }
     1568                }
    15671569
    1568         // Only send the DATA command if we have viable recipients
    1569         if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
    1570             throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
    1571         }
    1572         if ($this->SMTPKeepAlive) {
    1573             $this->smtp->reset();
    1574         } else {
    1575             $this->smtp->quit();
    1576             $this->smtp->close();
    1577         }
    1578         //Create error message for any bad addresses
    1579         if (count($bad_rcpt) > 0) {
    1580             $errstr = '';
    1581             foreach ($bad_rcpt as $bad) {
    1582                 $errstr .= $bad['to'] . ': ' . $bad['error'];
    1583             }
    1584             throw new phpmailerException(
    1585                 $this->lang('recipients_failed') . $errstr,
    1586                 self::STOP_CONTINUE
    1587             );
    1588         }
    1589         return true;
    1590     }
     1570                // Only send the DATA command if we have viable recipients
     1571                if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
     1572                        throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
     1573                }
     1574                if ($this->SMTPKeepAlive) {
     1575                        $this->smtp->reset();
     1576                } else {
     1577                        $this->smtp->quit();
     1578                        $this->smtp->close();
     1579                }
     1580                //Create error message for any bad addresses
     1581                if (count($bad_rcpt) > 0) {
     1582                        $errstr = '';
     1583                        foreach ($bad_rcpt as $bad) {
     1584                                $errstr .= $bad['to'] . ': ' . $bad['error'];
     1585                        }
     1586                        throw new phpmailerException(
     1587                                $this->lang('recipients_failed') . $errstr,
     1588                                self::STOP_CONTINUE
     1589                        );
     1590                }
     1591                return true;
     1592        }
    15911593
    1592     /**
    1593     * Initiate a connection to an SMTP server.
    1594     * Returns false if the operation failed.
    1595     * @param array $options An array of options compatible with stream_context_create()
    1596     * @uses SMTP
    1597     * @access public
    1598     * @throws phpmailerException
    1599     * @return boolean
    1600     */
    1601     public function smtpConnect($options = null)
    1602     {
    1603         if (is_null($this->smtp)) {
    1604             $this->smtp = $this->getSMTPInstance();
    1605         }
     1594        /**
     1595        * Initiate a connection to an SMTP server.
     1596        * Returns false if the operation failed.
     1597        * @param array $options An array of options compatible with stream_context_create()
     1598        * @uses SMTP
     1599        * @access public
     1600        * @throws phpmailerException
     1601        * @return boolean
     1602        */
     1603        public function smtpConnect($options = null)
     1604        {
     1605                if (is_null($this->smtp)) {
     1606                        $this->smtp = $this->getSMTPInstance();
     1607                }
    16061608
    1607         //If no options are provided, use whatever is set in the instance
    1608         if (is_null($options)) {
    1609             $options = $this->SMTPOptions;
    1610         }
     1609                //If no options are provided, use whatever is set in the instance
     1610                if (is_null($options)) {
     1611                        $options = $this->SMTPOptions;
     1612                }
    16111613
    1612         // Already connected?
    1613         if ($this->smtp->connected()) {
    1614             return true;
    1615         }
     1614                // Already connected?
     1615                if ($this->smtp->connected()) {
     1616                        return true;
     1617                }
    16161618
    1617         $this->smtp->setTimeout($this->Timeout);
    1618         $this->smtp->setDebugLevel($this->SMTPDebug);
    1619         $this->smtp->setDebugOutput($this->Debugoutput);
    1620         $this->smtp->setVerp($this->do_verp);
    1621         $hosts = explode(';', $this->Host);
    1622         $lastexception = null;
     1619                $this->smtp->setTimeout($this->Timeout);
     1620                $this->smtp->setDebugLevel($this->SMTPDebug);
     1621                $this->smtp->setDebugOutput($this->Debugoutput);
     1622                $this->smtp->setVerp($this->do_verp);
     1623                $hosts = explode(';', $this->Host);
     1624                $lastexception = null;
    16231625
    1624         foreach ($hosts as $hostentry) {
    1625             $hostinfo = array();
    1626             if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
    1627                 // Not a valid host entry
    1628                 continue;
    1629             }
    1630             // $hostinfo[2]: optional ssl or tls prefix
    1631             // $hostinfo[3]: the hostname
    1632             // $hostinfo[4]: optional port number
    1633             // The host string prefix can temporarily override the current setting for SMTPSecure
    1634             // If it's not specified, the default value is used
    1635             $prefix = '';
    1636             $secure = $this->SMTPSecure;
    1637             $tls = ($this->SMTPSecure == 'tls');
    1638             if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
    1639                 $prefix = 'ssl://';
    1640                 $tls = false; // Can't have SSL and TLS at the same time
    1641                 $secure = 'ssl';
    1642             } elseif ($hostinfo[2] == 'tls') {
    1643                 $tls = true;
    1644                 // tls doesn't use a prefix
    1645                 $secure = 'tls';
    1646             }
    1647             //Do we need the OpenSSL extension?
    1648             $sslext = defined('OPENSSL_ALGO_SHA1');
    1649             if ('tls' === $secure or 'ssl' === $secure) {
    1650                 //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
    1651                 if (!$sslext) {
    1652                     throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
    1653                 }
    1654             }
    1655             $host = $hostinfo[3];
    1656             $port = $this->Port;
    1657             $tport = (integer)$hostinfo[4];
    1658             if ($tport > 0 and $tport < 65536) {
    1659                 $port = $tport;
    1660             }
    1661             if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
    1662                 try {
    1663                     if ($this->Helo) {
    1664                         $hello = $this->Helo;
    1665                     } else {
    1666                         $hello = $this->serverHostname();
    1667                     }
    1668                     $this->smtp->hello($hello);
    1669                     //Automatically enable TLS encryption if:
    1670                     // * it's not disabled
    1671                     // * we have openssl extension
    1672                     // * we are not already using SSL
    1673                     // * the server offers STARTTLS
    1674                     if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
    1675                         $tls = true;
    1676                     }
    1677                     if ($tls) {
    1678                         if (!$this->smtp->startTLS()) {
    1679                             throw new phpmailerException($this->lang('connect_host'));
    1680                         }
    1681                         // We must resend EHLO after TLS negotiation
    1682                         $this->smtp->hello($hello);
    1683                     }
    1684                     if ($this->SMTPAuth) {
    1685                         if (!$this->smtp->authenticate(
    1686                             $this->Username,
    1687                             $this->Password,
    1688                             $this->AuthType,
    1689                             $this->Realm,
    1690                             $this->Workstation
    1691                         )
    1692                         ) {
    1693                             throw new phpmailerException($this->lang('authenticate'));
    1694                         }
    1695                     }
    1696                     return true;
    1697                 } catch (phpmailerException $exc) {
    1698                     $lastexception = $exc;
    1699                     $this->edebug($exc->getMessage());
    1700                     // We must have connected, but then failed TLS or Auth, so close connection nicely
    1701                     $this->smtp->quit();
    1702                 }
    1703             }
    1704         }
    1705         // If we get here, all connection attempts have failed, so close connection hard
    1706         $this->smtp->close();
    1707         // As we've caught all exceptions, just report whatever the last one was
    1708         if ($this->exceptions and !is_null($lastexception)) {
    1709             throw $lastexception;
    1710         }
    1711         return false;
    1712     }
     1626                foreach ($hosts as $hostentry) {
     1627                        $hostinfo = array();
     1628                        if (!preg_match(
     1629                                '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
     1630                                trim($hostentry),
     1631                                $hostinfo
     1632                        )) {
     1633                                // Not a valid host entry
     1634                                $this->edebug('Ignoring invalid host: ' . $hostentry);
     1635                                continue;
     1636                        }
     1637                        // $hostinfo[2]: optional ssl or tls prefix
     1638                        // $hostinfo[3]: the hostname
     1639                        // $hostinfo[4]: optional port number
     1640                        // The host string prefix can temporarily override the current setting for SMTPSecure
     1641                        // If it's not specified, the default value is used
     1642                        $prefix = '';
     1643                        $secure = $this->SMTPSecure;
     1644                        $tls = ($this->SMTPSecure == 'tls');
     1645                        if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
     1646                                $prefix = 'ssl://';
     1647                                $tls = false; // Can't have SSL and TLS at the same time
     1648                                $secure = 'ssl';
     1649                        } elseif ($hostinfo[2] == 'tls') {
     1650                                $tls = true;
     1651                                // tls doesn't use a prefix
     1652                                $secure = 'tls';
     1653                        }
     1654                        //Do we need the OpenSSL extension?
     1655                        $sslext = defined('OPENSSL_ALGO_SHA1');
     1656                        if ('tls' === $secure or 'ssl' === $secure) {
     1657                                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
     1658                                if (!$sslext) {
     1659                                        throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
     1660                                }
     1661                        }
     1662                        $host = $hostinfo[3];
     1663                        $port = $this->Port;
     1664                        $tport = (integer)$hostinfo[4];
     1665                        if ($tport > 0 and $tport < 65536) {
     1666                                $port = $tport;
     1667                        }
     1668                        if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
     1669                                try {
     1670                                        if ($this->Helo) {
     1671                                                $hello = $this->Helo;
     1672                                        } else {
     1673                                                $hello = $this->serverHostname();
     1674                                        }
     1675                                        $this->smtp->hello($hello);
     1676                                        //Automatically enable TLS encryption if:
     1677                                        // * it's not disabled
     1678                                        // * we have openssl extension
     1679                                        // * we are not already using SSL
     1680                                        // * the server offers STARTTLS
     1681                                        if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
     1682                                                $tls = true;
     1683                                        }
     1684                                        if ($tls) {
     1685                                                if (!$this->smtp->startTLS()) {
     1686                                                        throw new phpmailerException($this->lang('connect_host'));
     1687                                                }
     1688                                                // We must resend EHLO after TLS negotiation
     1689                                                $this->smtp->hello($hello);
     1690                                        }
     1691                                        if ($this->SMTPAuth) {
     1692                                                if (!$this->smtp->authenticate(
     1693                                                        $this->Username,
     1694                                                        $this->Password,
     1695                                                        $this->AuthType,
     1696                                                        $this->Realm,
     1697                                                        $this->Workstation
     1698                                                )
     1699                                                ) {
     1700                                                        throw new phpmailerException($this->lang('authenticate'));
     1701                                                }
     1702                                        }
     1703                                        return true;
     1704                                } catch (phpmailerException $exc) {
     1705                                        $lastexception = $exc;
     1706                                        $this->edebug($exc->getMessage());
     1707                                        // We must have connected, but then failed TLS or Auth, so close connection nicely
     1708                                        $this->smtp->quit();
     1709                                }
     1710                        }
     1711                }
     1712                // If we get here, all connection attempts have failed, so close connection hard
     1713                $this->smtp->close();
     1714                // As we've caught all exceptions, just report whatever the last one was
     1715                if ($this->exceptions and !is_null($lastexception)) {
     1716                        throw $lastexception;
     1717                }
     1718                return false;
     1719        }
    17131720
    1714     /**
    1715     * Close the active SMTP session if one exists.
    1716     * @return void
    1717     */
    1718     public function smtpClose()
    1719     {
    1720         if (is_a($this->smtp, 'SMTP')) {
    1721             if ($this->smtp->connected()) {
    1722                 $this->smtp->quit();
    1723                 $this->smtp->close();
    1724             }
    1725         }
    1726     }
     1721        /**
     1722        * Close the active SMTP session if one exists.
     1723        * @return void
     1724        */
     1725        public function smtpClose()
     1726        {
     1727                if (is_a($this->smtp, 'SMTP')) {
     1728                        if ($this->smtp->connected()) {
     1729                                $this->smtp->quit();
     1730                                $this->smtp->close();
     1731                        }
     1732                }
     1733        }
    17271734
    1728     /**
    1729      * Set the language for error messages.
    1730      * Returns false if it cannot load the language file.
    1731      * The default language is English.
    1732      * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
    1733      * @param string $lang_path Path to the language file directory, with trailing separator (slash)
    1734      * @return boolean
    1735      * @access public
    1736      */
    1737     public function setLanguage($langcode = 'en', $lang_path = '')
    1738     {
    1739         // Backwards compatibility for renamed language codes
    1740         $renamed_langcodes = array(
    1741             'br' => 'pt_br',
    1742             'cz' => 'cs',
    1743             'dk' => 'da',
    1744             'no' => 'nb',
    1745             'se' => 'sv',
    1746         );
     1735        /**
     1736         * Set the language for error messages.
     1737         * Returns false if it cannot load the language file.
     1738         * The default language is English.
     1739         * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
     1740         * @param string $lang_path Path to the language file directory, with trailing separator (slash)
     1741         * @return boolean
     1742         * @access public
     1743         */
     1744        public function setLanguage($langcode = 'en', $lang_path = '')
     1745        {
     1746                // Backwards compatibility for renamed language codes
     1747                $renamed_langcodes = array(
     1748                        'br' => 'pt_br',
     1749                        'cz' => 'cs',
     1750                        'dk' => 'da',
     1751                        'no' => 'nb',
     1752                        'se' => 'sv',
     1753                        'sr' => 'rs'
     1754                );
    17471755
    1748         if (isset($renamed_langcodes[$langcode])) {
    1749             $langcode = $renamed_langcodes[$langcode];
    1750         }
     1756                if (isset($renamed_langcodes[$langcode])) {
     1757                        $langcode = $renamed_langcodes[$langcode];
     1758                }
    17511759
    1752         // Define full set of translatable strings in English
    1753         $PHPMAILER_LANG = array(
    1754             'authenticate' => 'SMTP Error: Could not authenticate.',
    1755             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
    1756             'data_not_accepted' => 'SMTP Error: data not accepted.',
    1757             'empty_message' => 'Message body empty',
    1758             'encoding' => 'Unknown encoding: ',
    1759             'execute' => 'Could not execute: ',
    1760             'file_access' => 'Could not access file: ',
    1761             'file_open' => 'File Error: Could not open file: ',
    1762             'from_failed' => 'The following From address failed: ',
    1763             'instantiate' => 'Could not instantiate mail function.',
    1764             'invalid_address' => 'Invalid address: ',
    1765             'mailer_not_supported' => ' mailer is not supported.',
    1766             'provide_address' => 'You must provide at least one recipient email address.',
    1767             'recipients_failed' => 'SMTP Error: The following recipients failed: ',
    1768             'signing' => 'Signing Error: ',
    1769             'smtp_connect_failed' => 'SMTP connect() failed.',
    1770             'smtp_error' => 'SMTP server error: ',
    1771             'variable_set' => 'Cannot set or reset variable: ',
    1772             'extension_missing' => 'Extension missing: '
    1773         );
    1774         if (empty($lang_path)) {
    1775             // Calculate an absolute path so it can work if CWD is not here
    1776             $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
    1777         }
    1778         //Validate $langcode
    1779         if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
    1780             $langcode = 'en';
    1781         }
    1782         $foundlang = true;
    1783         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
    1784         // There is no English translation file
    1785         if ($langcode != 'en') {
    1786             // Make sure language file path is readable
    1787             if (!is_readable($lang_file)) {
    1788                 $foundlang = false;
    1789             } else {
    1790                 // Overwrite language-specific strings.
    1791                 // This way we'll never have missing translation keys.
    1792                 $foundlang = include $lang_file;
    1793             }
    1794         }
    1795         $this->language = $PHPMAILER_LANG;
    1796         return (boolean)$foundlang; // Returns false if language not found
    1797     }
     1760                // Define full set of translatable strings in English
     1761                $PHPMAILER_LANG = array(
     1762                        'authenticate' => 'SMTP Error: Could not authenticate.',
     1763                        'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
     1764                        'data_not_accepted' => 'SMTP Error: data not accepted.',
     1765                        'empty_message' => 'Message body empty',
     1766                        'encoding' => 'Unknown encoding: ',
     1767                        'execute' => 'Could not execute: ',
     1768                        'file_access' => 'Could not access file: ',
     1769                        'file_open' => 'File Error: Could not open file: ',
     1770                        'from_failed' => 'The following From address failed: ',
     1771                        'instantiate' => 'Could not instantiate mail function.',
     1772                        'invalid_address' => 'Invalid address: ',
     1773                        'mailer_not_supported' => ' mailer is not supported.',
     1774                        'provide_address' => 'You must provide at least one recipient email address.',
     1775                        'recipients_failed' => 'SMTP Error: The following recipients failed: ',
     1776                        'signing' => 'Signing Error: ',
     1777                        'smtp_connect_failed' => 'SMTP connect() failed.',
     1778                        'smtp_error' => 'SMTP server error: ',
     1779                        'variable_set' => 'Cannot set or reset variable: ',
     1780                        'extension_missing' => 'Extension missing: '
     1781                );
     1782                if (empty($lang_path)) {
     1783                        // Calculate an absolute path so it can work if CWD is not here
     1784                        $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
     1785                }
     1786                //Validate $langcode
     1787                if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
     1788                        $langcode = 'en';
     1789                }
     1790                $foundlang = true;
     1791                $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
     1792                // There is no English translation file
     1793                if ($langcode != 'en') {
     1794                        // Make sure language file path is readable
     1795                        if (!is_readable($lang_file)) {
     1796                                $foundlang = false;
     1797                        } else {
     1798                                // Overwrite language-specific strings.
     1799                                // This way we'll never have missing translation keys.
     1800                                $foundlang = include $lang_file;
     1801                        }
     1802                }
     1803                $this->language = $PHPMAILER_LANG;
     1804                return (boolean)$foundlang; // Returns false if language not found
     1805        }
    17981806
    1799     /**
    1800     * Get the array of strings for the current language.
    1801     * @return array
    1802     */
    1803     public function getTranslations()
    1804     {
    1805         return $this->language;
    1806     }
     1807        /**
     1808        * Get the array of strings for the current language.
     1809        * @return array
     1810        */
     1811        public function getTranslations()
     1812        {
     1813                return $this->language;
     1814        }
    18071815
    1808     /**
    1809     * Create recipient headers.
    1810     * @access public
    1811     * @param string $type
    1812     * @param array $addr An array of recipient,
    1813     * where each recipient is a 2-element indexed array with element 0 containing an address
    1814     * and element 1 containing a name, like:
    1815     * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
    1816     * @return string
    1817     */
    1818     public function addrAppend($type, $addr)
    1819     {
    1820         $addresses = array();
    1821         foreach ($addr as $address) {
    1822             $addresses[] = $this->addrFormat($address);
    1823         }
    1824         return $type . ': ' . implode(', ', $addresses) . $this->LE;
    1825     }
     1816        /**
     1817        * Create recipient headers.
     1818        * @access public
     1819        * @param string $type
     1820        * @param array $addr An array of recipient,
     1821        * where each recipient is a 2-element indexed array with element 0 containing an address
     1822        * and element 1 containing a name, like:
     1823        * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
     1824        * @return string
     1825        */
     1826        public function addrAppend($type, $addr)
     1827        {
     1828                $addresses = array();
     1829                foreach ($addr as $address) {
     1830                        $addresses[] = $this->addrFormat($address);
     1831                }
     1832                return $type . ': ' . implode(', ', $addresses) . $this->LE;
     1833        }
    18261834
    1827     /**
    1828     * Format an address for use in a message header.
    1829     * @access public
    1830     * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
    1831      *      like array('joe@example.com', 'Joe User')
    1832     * @return string
    1833     */
    1834     public function addrFormat($addr)
    1835     {
    1836         if (empty($addr[1])) { // No name provided
    1837             return $this->secureHeader($addr[0]);
    1838         } else {
    1839             return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
    1840                 $addr[0]
    1841             ) . '>';
    1842         }
    1843     }
     1835        /**
     1836        * Format an address for use in a message header.
     1837        * @access public
     1838        * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
     1839         *        like array('joe@example.com', 'Joe User')
     1840        * @return string
     1841        */
     1842        public function addrFormat($addr)
     1843        {
     1844                if (empty($addr[1])) { // No name provided
     1845                        return $this->secureHeader($addr[0]);
     1846                } else {
     1847                        return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
     1848                                $addr[0]
     1849                        ) . '>';
     1850                }
     1851        }
    18441852
    1845     /**
    1846     * Word-wrap message.
    1847     * For use with mailers that do not automatically perform wrapping
    1848     * and for quoted-printable encoded messages.
    1849     * Original written by philippe.
    1850     * @param string $message The message to wrap
    1851     * @param integer $length The line length to wrap to
    1852     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
    1853     * @access public
    1854     * @return string
    1855     */
    1856     public function wrapText($message, $length, $qp_mode = false)
    1857     {
    1858         if ($qp_mode) {
    1859             $soft_break = sprintf(' =%s', $this->LE);
    1860         } else {
    1861             $soft_break = $this->LE;
    1862         }
    1863         // If utf-8 encoding is used, we will need to make sure we don't
    1864         // split multibyte characters when we wrap
    1865         $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
    1866         $lelen = strlen($this->LE);
    1867         $crlflen = strlen(self::CRLF);
     1853        /**
     1854        * Word-wrap message.
     1855        * For use with mailers that do not automatically perform wrapping
     1856        * and for quoted-printable encoded messages.
     1857        * Original written by philippe.
     1858        * @param string $message The message to wrap
     1859        * @param integer $length The line length to wrap to
     1860        * @param boolean $qp_mode Whether to run in Quoted-Printable mode
     1861        * @access public
     1862        * @return string
     1863        */
     1864        public function wrapText($message, $length, $qp_mode = false)
     1865        {
     1866                if ($qp_mode) {
     1867                        $soft_break = sprintf(' =%s', $this->LE);
     1868                } else {
     1869                        $soft_break = $this->LE;
     1870                }
     1871                // If utf-8 encoding is used, we will need to make sure we don't
     1872                // split multibyte characters when we wrap
     1873                $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
     1874                $lelen = strlen($this->LE);
     1875                $crlflen = strlen(self::CRLF);
    18681876
    1869         $message = $this->fixEOL($message);
    1870         //Remove a trailing line break
    1871         if (substr($message, -$lelen) == $this->LE) {
    1872             $message = substr($message, 0, -$lelen);
    1873         }
     1877                $message = $this->fixEOL($message);
     1878                //Remove a trailing line break
     1879                if (substr($message, -$lelen) == $this->LE) {
     1880                        $message = substr($message, 0, -$lelen);
     1881                }
    18741882
    1875         //Split message into lines
    1876         $lines = explode($this->LE, $message);
    1877         //Message will be rebuilt in here
    1878         $message = '';
    1879         foreach ($lines as $line) {
    1880             $words = explode(' ', $line);
    1881             $buf = '';
    1882             $firstword = true;
    1883             foreach ($words as $word) {
    1884                 if ($qp_mode and (strlen($word) > $length)) {
    1885                     $space_left = $length - strlen($buf) - $crlflen;
    1886                     if (!$firstword) {
    1887                         if ($space_left > 20) {
    1888                             $len = $space_left;
    1889                             if ($is_utf8) {
    1890                                 $len = $this->utf8CharBoundary($word, $len);
    1891                             } elseif (substr($word, $len - 1, 1) == '=') {
    1892                                 $len--;
    1893                             } elseif (substr($word, $len - 2, 1) == '=') {
    1894                                 $len -= 2;
    1895                             }
    1896                             $part = substr($word, 0, $len);
    1897                             $word = substr($word, $len);
    1898                             $buf .= ' ' . $part;
    1899                             $message .= $buf . sprintf('=%s', self::CRLF);
    1900                         } else {
    1901                             $message .= $buf . $soft_break;
    1902                         }
    1903                         $buf = '';
    1904                     }
    1905                     while (strlen($word) > 0) {
    1906                         if ($length <= 0) {
    1907                             break;
    1908                         }
    1909                         $len = $length;
    1910                         if ($is_utf8) {
    1911                             $len = $this->utf8CharBoundary($word, $len);
    1912                         } elseif (substr($word, $len - 1, 1) == '=') {
    1913                             $len--;
    1914                         } elseif (substr($word, $len - 2, 1) == '=') {
    1915                             $len -= 2;
    1916                         }
    1917                         $part = substr($word, 0, $len);
    1918                         $word = substr($word, $len);
     1883                //Split message into lines
     1884                $lines = explode($this->LE, $message);
     1885                //Message will be rebuilt in here
     1886                $message = '';
     1887                foreach ($lines as $line) {
     1888                        $words = explode(' ', $line);
     1889                        $buf = '';
     1890                        $firstword = true;
     1891                        foreach ($words as $word) {
     1892                                if ($qp_mode and (strlen($word) > $length)) {
     1893                                        $space_left = $length - strlen($buf) - $crlflen;
     1894                                        if (!$firstword) {
     1895                                                if ($space_left > 20) {
     1896                                                        $len = $space_left;
     1897                                                        if ($is_utf8) {
     1898                                                                $len = $this->utf8CharBoundary($word, $len);
     1899                                                        } elseif (substr($word, $len - 1, 1) == '=') {
     1900                                                                $len--;
     1901                                                        } elseif (substr($word, $len - 2, 1) == '=') {
     1902                                                                $len -= 2;
     1903                                                        }
     1904                                                        $part = substr($word, 0, $len);
     1905                                                        $word = substr($word, $len);
     1906                                                        $buf .= ' ' . $part;
     1907                                                        $message .= $buf . sprintf('=%s', self::CRLF);
     1908                                                } else {
     1909                                                        $message .= $buf . $soft_break;
     1910                                                }
     1911                                                $buf = '';
     1912                                        }
     1913                                        while (strlen($word) > 0) {
     1914                                                if ($length <= 0) {
     1915                                                        break;
     1916                                                }
     1917                                                $len = $length;
     1918                                                if ($is_utf8) {
     1919                                                        $len = $this->utf8CharBoundary($word, $len);
     1920                                                } elseif (substr($word, $len - 1, 1) == '=') {
     1921                                                        $len--;
     1922                                                } elseif (substr($word, $len - 2, 1) == '=') {
     1923                                                        $len -= 2;
     1924                                                }
     1925                                                $part = substr($word, 0, $len);
     1926                                                $word = substr($word, $len);
    19191927
    1920                         if (strlen($word) > 0) {
    1921                             $message .= $part . sprintf('=%s', self::CRLF);
    1922                         } else {
    1923                             $buf = $part;
    1924                         }
    1925                     }
    1926                 } else {
    1927                     $buf_o = $buf;
    1928                     if (!$firstword) {
    1929                         $buf .= ' ';
    1930                     }
    1931                     $buf .= $word;
     1928                                                if (strlen($word) > 0) {
     1929                                                        $message .= $part . sprintf('=%s', self::CRLF);
     1930                                                } else {
     1931                                                        $buf = $part;
     1932                                                }
     1933                                        }
     1934                                } else {
     1935                                        $buf_o = $buf;
     1936                                        if (!$firstword) {
     1937                                                $buf .= ' ';
     1938                                        }
     1939                                        $buf .= $word;
    19321940
    1933                     if (strlen($buf) > $length and $buf_o != '') {
    1934                         $message .= $buf_o . $soft_break;
    1935                         $buf = $word;
    1936                     }
    1937                 }
    1938                 $firstword = false;
    1939             }
    1940             $message .= $buf . self::CRLF;
    1941         }
     1941                                        if (strlen($buf) > $length and $buf_o != '') {
     1942                                                $message .= $buf_o . $soft_break;
     1943                                                $buf = $word;
     1944                                        }
     1945                                }
     1946                                $firstword = false;
     1947                        }
     1948                        $message .= $buf . self::CRLF;
     1949                }
    19421950
    1943         return $message;
    1944     }
     1951                return $message;
     1952        }
    19451953
    1946     /**
    1947     * Find the last character boundary prior to $maxLength in a utf-8
    1948     * quoted-printable encoded string.
    1949     * Original written by Colin Brown.
    1950     * @access public
    1951     * @param string $encodedText utf-8 QP text
    1952     * @param integer $maxLength Find the last character boundary prior to this length
    1953     * @return integer
    1954     */
    1955     public function utf8CharBoundary($encodedText, $maxLength)
    1956     {
    1957         $foundSplitPos = false;
    1958         $lookBack = 3;
    1959         while (!$foundSplitPos) {
    1960             $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
    1961             $encodedCharPos = strpos($lastChunk, '=');
    1962             if (false !== $encodedCharPos) {
    1963                 // Found start of encoded character byte within $lookBack block.
    1964                 // Check the encoded byte value (the 2 chars after the '=')
    1965                 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
    1966                 $dec = hexdec($hex);
    1967                 if ($dec < 128) {
    1968                     // Single byte character.
    1969                     // If the encoded char was found at pos 0, it will fit
    1970                     // otherwise reduce maxLength to start of the encoded char
    1971                     if ($encodedCharPos > 0) {
    1972                         $maxLength = $maxLength - ($lookBack - $encodedCharPos);
    1973                     }
    1974                     $foundSplitPos = true;
    1975                 } elseif ($dec >= 192) {
    1976                     // First byte of a multi byte character
    1977                     // Reduce maxLength to split at start of character
    1978                     $maxLength = $maxLength - ($lookBack - $encodedCharPos);
    1979                     $foundSplitPos = true;
    1980                 } elseif ($dec < 192) {
    1981                     // Middle byte of a multi byte character, look further back
    1982                     $lookBack += 3;
    1983                 }
    1984             } else {
    1985                 // No encoded character found
    1986                 $foundSplitPos = true;
    1987             }
    1988         }
    1989         return $maxLength;
    1990     }
     1954        /**
     1955        * Find the last character boundary prior to $maxLength in a utf-8
     1956        * quoted-printable encoded string.
     1957        * Original written by Colin Brown.
     1958        * @access public
     1959        * @param string $encodedText utf-8 QP text
     1960        * @param integer $maxLength Find the last character boundary prior to this length
     1961        * @return integer
     1962        */
     1963        public function utf8CharBoundary($encodedText, $maxLength)
     1964        {
     1965                $foundSplitPos = false;
     1966                $lookBack = 3;
     1967                while (!$foundSplitPos) {
     1968                        $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
     1969                        $encodedCharPos = strpos($lastChunk, '=');
     1970                        if (false !== $encodedCharPos) {
     1971                                // Found start of encoded character byte within $lookBack block.
     1972                                // Check the encoded byte value (the 2 chars after the '=')
     1973                                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
     1974                                $dec = hexdec($hex);
     1975                                if ($dec < 128) {
     1976                                        // Single byte character.
     1977                                        // If the encoded char was found at pos 0, it will fit
     1978                                        // otherwise reduce maxLength to start of the encoded char
     1979                                        if ($encodedCharPos > 0) {
     1980                                                $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     1981                                        }
     1982                                        $foundSplitPos = true;
     1983                                } elseif ($dec >= 192) {
     1984                                        // First byte of a multi byte character
     1985                                        // Reduce maxLength to split at start of character
     1986                                        $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     1987                                        $foundSplitPos = true;
     1988                                } elseif ($dec < 192) {
     1989                                        // Middle byte of a multi byte character, look further back
     1990                                        $lookBack += 3;
     1991                                }
     1992                        } else {
     1993                                // No encoded character found
     1994                                $foundSplitPos = true;
     1995                        }
     1996                }
     1997                return $maxLength;
     1998        }
    19911999
    1992     /**
    1993     * Apply word wrapping to the message body.
    1994     * Wraps the message body to the number of chars set in the WordWrap property.
    1995     * You should only do this to plain-text bodies as wrapping HTML tags may break them.
    1996     * This is called automatically by createBody(), so you don't need to call it yourself.
    1997     * @access public
    1998     * @return void
    1999     */
    2000     public function setWordWrap()
    2001     {
    2002         if ($this->WordWrap < 1) {
    2003             return;
    2004         }
     2000        /**
     2001        * Apply word wrapping to the message body.
     2002        * Wraps the message body to the number of chars set in the WordWrap property.
     2003        * You should only do this to plain-text bodies as wrapping HTML tags may break them.
     2004        * This is called automatically by createBody(), so you don't need to call it yourself.
     2005        * @access public
     2006        * @return void
     2007        */
     2008        public function setWordWrap()
     2009        {
     2010                if ($this->WordWrap < 1) {
     2011                        return;
     2012                }
    20052013
    2006         switch ($this->message_type) {
    2007             case 'alt':
    2008             case 'alt_inline':
    2009             case 'alt_attach':
    2010             case 'alt_inline_attach':
    2011                 $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
    2012                 break;
    2013             default:
    2014                 $this->Body = $this->wrapText($this->Body, $this->WordWrap);
    2015                 break;
    2016         }
    2017     }
     2014                switch ($this->message_type) {
     2015                        case 'alt':
     2016                        case 'alt_inline':
     2017                        case 'alt_attach':
     2018                        case 'alt_inline_attach':
     2019                                $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
     2020                                break;
     2021                        default:
     2022                                $this->Body = $this->wrapText($this->Body, $this->WordWrap);
     2023                                break;
     2024                }
     2025        }
    20182026
    2019     /**
    2020     * Assemble message headers.
    2021     * @access public
    2022     * @return string The assembled headers
    2023     */
    2024     public function createHeader()
    2025     {
    2026         $result = '';
     2027        /**
     2028        * Assemble message headers.
     2029        * @access public
     2030        * @return string The assembled headers
     2031        */
     2032        public function createHeader()
     2033        {
     2034                $result = '';
    20272035
    2028         if ($this->MessageDate == '') {
    2029             $this->MessageDate = self::rfcDate();
    2030         }
    2031         $result .= $this->headerLine('Date', $this->MessageDate);
     2036                $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
    20322037
    2033         // To be created automatically by mail()
    2034         if ($this->SingleTo) {
    2035             if ($this->Mailer != 'mail') {
    2036                 foreach ($this->to as $toaddr) {
    2037                     $this->SingleToArray[] = $this->addrFormat($toaddr);
    2038                 }
    2039             }
    2040         } else {
    2041             if (count($this->to) > 0) {
    2042                 if ($this->Mailer != 'mail') {
    2043                     $result .= $this->addrAppend('To', $this->to);
    2044                 }
    2045             } elseif (count($this->cc) == 0) {
    2046                 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
    2047             }
    2048         }
     2038                // To be created automatically by mail()
     2039                if ($this->SingleTo) {
     2040                        if ($this->Mailer != 'mail') {
     2041                                foreach ($this->to as $toaddr) {
     2042                                        $this->SingleToArray[] = $this->addrFormat($toaddr);
     2043                                }
     2044                        }
     2045                } else {
     2046                        if (count($this->to) > 0) {
     2047                                if ($this->Mailer != 'mail') {
     2048                                        $result .= $this->addrAppend('To', $this->to);
     2049                                }
     2050                        } elseif (count($this->cc) == 0) {
     2051                                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
     2052                        }
     2053                }
    20492054
    2050         $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
     2055                $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
    20512056
    2052         // sendmail and mail() extract Cc from the header before sending
    2053         if (count($this->cc) > 0) {
    2054             $result .= $this->addrAppend('Cc', $this->cc);
    2055         }
     2057                // sendmail and mail() extract Cc from the header before sending
     2058                if (count($this->cc) > 0) {
     2059                        $result .= $this->addrAppend('Cc', $this->cc);
     2060                }
    20562061
    2057         // sendmail and mail() extract Bcc from the header before sending
    2058         if ((
    2059                 $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
    2060             )
    2061             and count($this->bcc) > 0
    2062         ) {
    2063             $result .= $this->addrAppend('Bcc', $this->bcc);
    2064         }
     2062                // sendmail and mail() extract Bcc from the header before sending
     2063                if ((
     2064                                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
     2065                        )
     2066                        and count($this->bcc) > 0
     2067                ) {
     2068                        $result .= $this->addrAppend('Bcc', $this->bcc);
     2069                }
    20652070
    2066         if (count($this->ReplyTo) > 0) {
    2067             $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
    2068         }
     2071                if (count($this->ReplyTo) > 0) {
     2072                        $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
     2073                }
    20692074
    2070         // mail() sets the subject itself
    2071         if ($this->Mailer != 'mail') {
    2072             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
    2073         }
     2075                // mail() sets the subject itself
     2076                if ($this->Mailer != 'mail') {
     2077                        $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
     2078                }
    20742079
    2075         // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
    2076         // https://tools.ietf.org/html/rfc5322#section-3.6.4
    2077         if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
    2078             $this->lastMessageID = $this->MessageID;
    2079         } else {
    2080             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
    2081         }
    2082         $result .= $this->headerLine('Message-ID', $this->lastMessageID);
    2083         if (!is_null($this->Priority)) {
    2084             $result .= $this->headerLine('X-Priority', $this->Priority);
    2085         }
    2086         if ($this->XMailer == '') {
    2087             $result .= $this->headerLine(
    2088                 'X-Mailer',
    2089                 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
    2090             );
    2091         } else {
    2092             $myXmailer = trim($this->XMailer);
    2093             if ($myXmailer) {
    2094                 $result .= $this->headerLine('X-Mailer', $myXmailer);
    2095             }
    2096         }
     2080                // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
     2081                // https://tools.ietf.org/html/rfc5322#section-3.6.4
     2082                if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
     2083                        $this->lastMessageID = $this->MessageID;
     2084                } else {
     2085                        $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
     2086                }
     2087                $result .= $this->headerLine('Message-ID', $this->lastMessageID);
     2088                if (!is_null($this->Priority)) {
     2089                        $result .= $this->headerLine('X-Priority', $this->Priority);
     2090                }
     2091                if ($this->XMailer == '') {
     2092                        $result .= $this->headerLine(
     2093                                'X-Mailer',
     2094                                'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
     2095                        );
     2096                } else {
     2097                        $myXmailer = trim($this->XMailer);
     2098                        if ($myXmailer) {
     2099                                $result .= $this->headerLine('X-Mailer', $myXmailer);
     2100                        }
     2101                }
    20972102
    2098         if ($this->ConfirmReadingTo != '') {
    2099             $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
    2100         }
     2103                if ($this->ConfirmReadingTo != '') {
     2104                        $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
     2105                }
    21012106
    2102         // Add custom headers
    2103         foreach ($this->CustomHeader as $header) {
    2104             $result .= $this->headerLine(
    2105                 trim($header[0]),
    2106                 $this->encodeHeader(trim($header[1]))
    2107             );
    2108         }
    2109         if (!$this->sign_key_file) {
    2110             $result .= $this->headerLine('MIME-Version', '1.0');
    2111             $result .= $this->getMailMIME();
    2112         }
     2107                // Add custom headers
     2108                foreach ($this->CustomHeader as $header) {
     2109                        $result .= $this->headerLine(
     2110                                trim($header[0]),
     2111                                $this->encodeHeader(trim($header[1]))
     2112                        );
     2113                }
     2114                if (!$this->sign_key_file) {
     2115                        $result .= $this->headerLine('MIME-Version', '1.0');
     2116                        $result .= $this->getMailMIME();
     2117                }
    21132118
    2114         return $result;
    2115     }
     2119                return $result;
     2120        }
    21162121
    2117     /**
    2118     * Get the message MIME type headers.
    2119     * @access public
    2120     * @return string
    2121     */
    2122     public function getMailMIME()
    2123     {
    2124         $result = '';
    2125         $ismultipart = true;
    2126         switch ($this->message_type) {
    2127             case 'inline':
    2128                 $result .= $this->headerLine('Content-Type', 'multipart/related;');
    2129                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
    2130                 break;
    2131             case 'attach':
    2132             case 'inline_attach':
    2133             case 'alt_attach':
    2134             case 'alt_inline_attach':
    2135                 $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
    2136                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
    2137                 break;
    2138             case 'alt':
    2139             case 'alt_inline':
    2140                 $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
    2141                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
    2142                 break;
    2143             default:
    2144                 // Catches case 'plain': and case '':
    2145                 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
    2146                 $ismultipart = false;
    2147                 break;
    2148         }
    2149         // RFC1341 part 5 says 7bit is assumed if not specified
    2150         if ($this->Encoding != '7bit') {
    2151             // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
    2152             if ($ismultipart) {
    2153                 if ($this->Encoding == '8bit') {
    2154                     $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
    2155                 }
    2156                 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
    2157             } else {
    2158                 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
    2159             }
    2160         }
     2122        /**
     2123        * Get the message MIME type headers.
     2124        * @access public
     2125        * @return string
     2126        */
     2127        public function getMailMIME()
     2128        {
     2129                $result = '';
     2130                $ismultipart = true;
     2131                switch ($this->message_type) {
     2132                        case 'inline':
     2133                                $result .= $this->headerLine('Content-Type', 'multipart/related;');
     2134                                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     2135                                break;
     2136                        case 'attach':
     2137                        case 'inline_attach':
     2138                        case 'alt_attach':
     2139                        case 'alt_inline_attach':
     2140                                $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
     2141                                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     2142                                break;
     2143                        case 'alt':
     2144                        case 'alt_inline':
     2145                                $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
     2146                                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     2147                                break;
     2148                        default:
     2149                                // Catches case 'plain': and case '':
     2150                                $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
     2151                                $ismultipart = false;
     2152                                break;
     2153                }
     2154                // RFC1341 part 5 says 7bit is assumed if not specified
     2155                if ($this->Encoding != '7bit') {
     2156                        // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
     2157                        if ($ismultipart) {
     2158                                if ($this->Encoding == '8bit') {
     2159                                        $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
     2160                                }
     2161                                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
     2162                        } else {
     2163                                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
     2164                        }
     2165                }
    21612166
    2162         if ($this->Mailer != 'mail') {
    2163             $result .= $this->LE;
    2164         }
     2167                if ($this->Mailer != 'mail') {
     2168                        $result .= $this->LE;
     2169                }
    21652170
    2166         return $result;
    2167     }
     2171                return $result;
     2172        }
    21682173
    2169     /**
    2170     * Returns the whole MIME message.
    2171     * Includes complete headers and body.
    2172     * Only valid post preSend().
    2173     * @see PHPMailer::preSend()
    2174     * @access public
    2175     * @return string
    2176     */
    2177     public function getSentMIMEMessage()
    2178     {
    2179         return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
    2180     }
     2174        /**
     2175        * Returns the whole MIME message.
     2176        * Includes complete headers and body.
     2177        * Only valid post preSend().
     2178        * @see PHPMailer::preSend()
     2179        * @access public
     2180        * @return string
     2181        */
     2182        public function getSentMIMEMessage()
     2183        {
     2184                return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
     2185        }
    21812186
    2182     /**
    2183     * Create unique ID
    2184     * @return string
    2185     */
    2186     protected function generateId() {
    2187         return md5(uniqid(time()));
    2188     }
     2187        /**
     2188        * Create unique ID
     2189        * @return string
     2190        */
     2191        protected function generateId() {
     2192                return md5(uniqid(time()));
     2193        }
    21892194
    2190     /**
    2191     * Assemble the message body.
    2192     * Returns an empty string on failure.
    2193     * @access public
    2194     * @throws phpmailerException
    2195     * @return string The assembled message body
    2196     */
    2197     public function createBody()
    2198     {
    2199         $body = '';
    2200         //Create unique IDs and preset boundaries
    2201         $this->uniqueid = $this->generateId();
    2202         $this->boundary[1] = 'b1_' . $this->uniqueid;
    2203         $this->boundary[2] = 'b2_' . $this->uniqueid;
    2204         $this->boundary[3] = 'b3_' . $this->uniqueid;
     2195        /**
     2196        * Assemble the message body.
     2197        * Returns an empty string on failure.
     2198        * @access public
     2199        * @throws phpmailerException
     2200        * @return string The assembled message body
     2201        */
     2202        public function createBody()
     2203        {
     2204                $body = '';
     2205                //Create unique IDs and preset boundaries
     2206                $this->uniqueid = $this->generateId();
     2207                $this->boundary[1] = 'b1_' . $this->uniqueid;
     2208                $this->boundary[2] = 'b2_' . $this->uniqueid;
     2209                $this->boundary[3] = 'b3_' . $this->uniqueid;
    22052210
    2206         if ($this->sign_key_file) {
    2207             $body .= $this->getMailMIME() . $this->LE;
    2208         }
     2211                if ($this->sign_key_file) {
     2212                        $body .= $this->getMailMIME() . $this->LE;
     2213                }
    22092214
    2210         $this->setWordWrap();
     2215                $this->setWordWrap();
    22112216
    2212         $bodyEncoding = $this->Encoding;
    2213         $bodyCharSet = $this->CharSet;
    2214         //Can we do a 7-bit downgrade?
    2215         if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
    2216             $bodyEncoding = '7bit';
    2217             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    2218             $bodyCharSet = 'us-ascii';
    2219         }
    2220         //If lines are too long, and we're not already using an encoding that will shorten them,
    2221         //change to quoted-printable transfer encoding for the body part only
    2222         if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
    2223             $bodyEncoding = 'quoted-printable';
    2224         }
     2217                $bodyEncoding = $this->Encoding;
     2218                $bodyCharSet = $this->CharSet;
     2219                //Can we do a 7-bit downgrade?
     2220                if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
     2221                        $bodyEncoding = '7bit';
     2222                        //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
     2223                        $bodyCharSet = 'us-ascii';
     2224                }
     2225                //If lines are too long, and we're not already using an encoding that will shorten them,
     2226                //change to quoted-printable transfer encoding for the body part only
     2227                if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
     2228                        $bodyEncoding = 'quoted-printable';
     2229                }
    22252230
    2226         $altBodyEncoding = $this->Encoding;
    2227         $altBodyCharSet = $this->CharSet;
    2228         //Can we do a 7-bit downgrade?
    2229         if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
    2230             $altBodyEncoding = '7bit';
    2231             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    2232             $altBodyCharSet = 'us-ascii';
    2233         }
    2234         //If lines are too long, and we're not already using an encoding that will shorten them,
    2235         //change to quoted-printable transfer encoding for the alt body part only
    2236         if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
    2237             $altBodyEncoding = 'quoted-printable';
    2238         }
    2239         //Use this as a preamble in all multipart message types
    2240         $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
    2241         switch ($this->message_type) {
    2242             case 'inline':
    2243                 $body .= $mimepre;
    2244                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
    2245                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2246                 $body .= $this->LE . $this->LE;
    2247                 $body .= $this->attachAll('inline', $this->boundary[1]);
    2248                 break;
    2249             case 'attach':
    2250                 $body .= $mimepre;
    2251                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
    2252                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2253                 $body .= $this->LE . $this->LE;
    2254                 $body .= $this->attachAll('attachment', $this->boundary[1]);
    2255                 break;
    2256             case 'inline_attach':
    2257                 $body .= $mimepre;
    2258                 $body .= $this->textLine('--' . $this->boundary[1]);
    2259                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
    2260                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
    2261                 $body .= $this->LE;
    2262                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
    2263                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2264                 $body .= $this->LE . $this->LE;
    2265                 $body .= $this->attachAll('inline', $this->boundary[2]);
    2266                 $body .= $this->LE;
    2267                 $body .= $this->attachAll('attachment', $this->boundary[1]);
    2268                 break;
    2269             case 'alt':
    2270                 $body .= $mimepre;
    2271                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
    2272                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
    2273                 $body .= $this->LE . $this->LE;
    2274                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
    2275                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2276                 $body .= $this->LE . $this->LE;
    2277                 if (!empty($this->Ical)) {
    2278                     $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
    2279                     $body .= $this->encodeString($this->Ical, $this->Encoding);
    2280                     $body .= $this->LE . $this->LE;
    2281                 }
    2282                 $body .= $this->endBoundary($this->boundary[1]);
    2283                 break;
    2284             case 'alt_inline':
    2285                 $body .= $mimepre;
    2286                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
    2287                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
    2288                 $body .= $this->LE . $this->LE;
    2289                 $body .= $this->textLine('--' . $this->boundary[1]);
    2290                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
    2291                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
    2292                 $body .= $this->LE;
    2293                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
    2294                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2295                 $body .= $this->LE . $this->LE;
    2296                 $body .= $this->attachAll('inline', $this->boundary[2]);
    2297                 $body .= $this->LE;
    2298                 $body .= $this->endBoundary($this->boundary[1]);
    2299                 break;
    2300             case 'alt_attach':
    2301                 $body .= $mimepre;
    2302                 $body .= $this->textLine('--' . $this->boundary[1]);
    2303                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
    2304                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
    2305                 $body .= $this->LE;
    2306                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
    2307                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
    2308                 $body .= $this->LE . $this->LE;
    2309                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
    2310                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2311                 $body .= $this->LE . $this->LE;
    2312                 $body .= $this->endBoundary($this->boundary[2]);
    2313                 $body .= $this->LE;
    2314                 $body .= $this->attachAll('attachment', $this->boundary[1]);
    2315                 break;
    2316             case 'alt_inline_attach':
    2317                 $body .= $mimepre;
    2318                 $body .= $this->textLine('--' . $this->boundary[1]);
    2319                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
    2320                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
    2321                 $body .= $this->LE;
    2322                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
    2323                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
    2324                 $body .= $this->LE . $this->LE;
    2325                 $body .= $this->textLine('--' . $this->boundary[2]);
    2326                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
    2327                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
    2328                 $body .= $this->LE;
    2329                 $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
    2330                 $body .= $this->encodeString($this->Body, $bodyEncoding);
    2331                 $body .= $this->LE . $this->LE;
    2332                 $body .= $this->attachAll('inline', $this->boundary[3]);
    2333                 $body .= $this->LE;
    2334                 $body .= $this->endBoundary($this->boundary[2]);
    2335                 $body .= $this->LE;
    2336                 $body .= $this->attachAll('attachment', $this->boundary[1]);
    2337                 break;
    2338             default:
    2339                 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
    2340                 //Reset the `Encoding` property in case we changed it for line length reasons
    2341                 $this->Encoding = $bodyEncoding;
    2342                 $body .= $this->encodeString($this->Body, $this->Encoding);
    2343                 break;
    2344         }
     2231                $altBodyEncoding = $this->Encoding;
     2232                $altBodyCharSet = $this->CharSet;
     2233                //Can we do a 7-bit downgrade?
     2234                if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
     2235                        $altBodyEncoding = '7bit';
     2236                        //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
     2237                        $altBodyCharSet = 'us-ascii';
     2238                }
     2239                //If lines are too long, and we're not already using an encoding that will shorten them,
     2240                //change to quoted-printable transfer encoding for the alt body part only
     2241                if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
     2242                        $altBodyEncoding = 'quoted-printable';
     2243                }
     2244                //Use this as a preamble in all multipart message types
     2245                $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
     2246                switch ($this->message_type) {
     2247                        case 'inline':
     2248                                $body .= $mimepre;
     2249                                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
     2250                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2251                                $body .= $this->LE . $this->LE;
     2252                                $body .= $this->attachAll('inline', $this->boundary[1]);
     2253                                break;
     2254                        case 'attach':
     2255                                $body .= $mimepre;
     2256                                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
     2257                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2258                                $body .= $this->LE . $this->LE;
     2259                                $body .= $this->attachAll('attachment', $this->boundary[1]);
     2260                                break;
     2261                        case 'inline_attach':
     2262                                $body .= $mimepre;
     2263                                $body .= $this->textLine('--' . $this->boundary[1]);
     2264                                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     2265                                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     2266                                $body .= $this->LE;
     2267                                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
     2268                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2269                                $body .= $this->LE . $this->LE;
     2270                                $body .= $this->attachAll('inline', $this->boundary[2]);
     2271                                $body .= $this->LE;
     2272                                $body .= $this->attachAll('attachment', $this->boundary[1]);
     2273                                break;
     2274                        case 'alt':
     2275                                $body .= $mimepre;
     2276                                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     2277                                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     2278                                $body .= $this->LE . $this->LE;
     2279                                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
     2280                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2281                                $body .= $this->LE . $this->LE;
     2282                                if (!empty($this->Ical)) {
     2283                                        $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
     2284                                        $body .= $this->encodeString($this->Ical, $this->Encoding);
     2285                                        $body .= $this->LE . $this->LE;
     2286                                }
     2287                                $body .= $this->endBoundary($this->boundary[1]);
     2288                                break;
     2289                        case 'alt_inline':
     2290                                $body .= $mimepre;
     2291                                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     2292                                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     2293                                $body .= $this->LE . $this->LE;
     2294                                $body .= $this->textLine('--' . $this->boundary[1]);
     2295                                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     2296                                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     2297                                $body .= $this->LE;
     2298                                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
     2299                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2300                                $body .= $this->LE . $this->LE;
     2301                                $body .= $this->attachAll('inline', $this->boundary[2]);
     2302                                $body .= $this->LE;
     2303                                $body .= $this->endBoundary($this->boundary[1]);
     2304                                break;
     2305                        case 'alt_attach':
     2306                                $body .= $mimepre;
     2307                                $body .= $this->textLine('--' . $this->boundary[1]);
     2308                                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
     2309                                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     2310                                $body .= $this->LE;
     2311                                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     2312                                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     2313                                $body .= $this->LE . $this->LE;
     2314                                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
     2315                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2316                                $body .= $this->LE . $this->LE;
     2317                                $body .= $this->endBoundary($this->boundary[2]);
     2318                                $body .= $this->LE;
     2319                                $body .= $this->attachAll('attachment', $this->boundary[1]);
     2320                                break;
     2321                        case 'alt_inline_attach':
     2322                                $body .= $mimepre;
     2323                                $body .= $this->textLine('--' . $this->boundary[1]);
     2324                                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
     2325                                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     2326                                $body .= $this->LE;
     2327                                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     2328                                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     2329                                $body .= $this->LE . $this->LE;
     2330                                $body .= $this->textLine('--' . $this->boundary[2]);
     2331                                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     2332                                $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
     2333                                $body .= $this->LE;
     2334                                $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
     2335                                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2336                                $body .= $this->LE . $this->LE;
     2337                                $body .= $this->attachAll('inline', $this->boundary[3]);
     2338                                $body .= $this->LE;
     2339                                $body .= $this->endBoundary($this->boundary[2]);
     2340                                $body .= $this->LE;
     2341                                $body .= $this->attachAll('attachment', $this->boundary[1]);
     2342                                break;
     2343                        default:
     2344                                // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
     2345                                //Reset the `Encoding` property in case we changed it for line length reasons
     2346                                $this->Encoding = $bodyEncoding;
     2347                                $body .= $this->encodeString($this->Body, $this->Encoding);
     2348                                break;
     2349                }
    23452350
    2346         if ($this->isError()) {
    2347             $body = '';
    2348         } elseif ($this->sign_key_file) {
    2349             try {
    2350                 if (!defined('PKCS7_TEXT')) {
    2351                     throw new phpmailerException($this->lang('extension_missing') . 'openssl');
    2352                 }
    2353                 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
    2354                 $file = tempnam(sys_get_temp_dir(), 'mail');
    2355                 if (false === file_put_contents($file, $body)) {
    2356                     throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
    2357                 }
    2358                 $signed = tempnam(sys_get_temp_dir(), 'signed');
    2359                 //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
    2360                 if (empty($this->sign_extracerts_file)) {
    2361                     $sign = @openssl_pkcs7_sign(
    2362                         $file,
    2363                         $signed,
    2364                         'file://' . realpath($this->sign_cert_file),
    2365                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
    2366                         null
    2367                     );
    2368                 } else {
    2369                     $sign = @openssl_pkcs7_sign(
    2370                         $file,
    2371                         $signed,
    2372                         'file://' . realpath($this->sign_cert_file),
    2373                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
    2374                         null,
    2375                         PKCS7_DETACHED,
    2376                         $this->sign_extracerts_file
    2377                     );
    2378                 }
    2379                 if ($sign) {
    2380                     @unlink($file);
    2381                     $body = file_get_contents($signed);
    2382                     @unlink($signed);
    2383                     //The message returned by openssl contains both headers and body, so need to split them up
    2384                     $parts = explode("\n\n", $body, 2);
    2385                     $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
    2386                     $body = $parts[1];
    2387                 } else {
    2388                     @unlink($file);
    2389                     @unlink($signed);
    2390                     throw new phpmailerException($this->lang('signing') . openssl_error_string());
    2391                 }
    2392             } catch (phpmailerException $exc) {
    2393                 $body = '';
    2394                 if ($this->exceptions) {
    2395                     throw $exc;
    2396                 }
    2397             }
    2398         }
    2399         return $body;
    2400     }
     2351                if ($this->isError()) {
     2352                        $body = '';
     2353                } elseif ($this->sign_key_file) {
     2354                        try {
     2355                                if (!defined('PKCS7_TEXT')) {
     2356                                        throw new phpmailerException($this->lang('extension_missing') . 'openssl');
     2357                                }
     2358                                // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
     2359                                $file = tempnam(sys_get_temp_dir(), 'mail');
     2360                                if (false === file_put_contents($file, $body)) {
     2361                                        throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
     2362                                }
     2363                                $signed = tempnam(sys_get_temp_dir(), 'signed');
     2364                                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
     2365                                if (empty($this->sign_extracerts_file)) {
     2366                                        $sign = @openssl_pkcs7_sign(
     2367                                                $file,
     2368                                                $signed,
     2369                                                'file://' . realpath($this->sign_cert_file),
     2370                                                array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
     2371                                                null
     2372                                        );
     2373                                } else {
     2374                                        $sign = @openssl_pkcs7_sign(
     2375                                                $file,
     2376                                                $signed,
     2377                                                'file://' . realpath($this->sign_cert_file),
     2378                                                array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
     2379                                                null,
     2380                                                PKCS7_DETACHED,
     2381                                                $this->sign_extracerts_file
     2382                                        );
     2383                                }
     2384                                if ($sign) {
     2385                                        @unlink($file);
     2386                                        $body = file_get_contents($signed);
     2387                                        @unlink($signed);
     2388                                        //The message returned by openssl contains both headers and body, so need to split them up
     2389                                        $parts = explode("\n\n", $body, 2);
     2390                                        $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
     2391                                        $body = $parts[1];
     2392                                } else {
     2393                                        @unlink($file);
     2394                                        @unlink($signed);
     2395                                        throw new phpmailerException($this->lang('signing') . openssl_error_string());
     2396                                }
     2397                        } catch (phpmailerException $exc) {
     2398                                $body = '';
     2399                                if ($this->exceptions) {
     2400                                        throw $exc;
     2401                                }
     2402                        }
     2403                }
     2404                return $body;
     2405        }
    24012406
    2402     /**
    2403     * Return the start of a message boundary.
    2404     * @access protected
    2405     * @param string $boundary
    2406     * @param string $charSet
    2407     * @param string $contentType
    2408     * @param string $encoding
    2409     * @return string
    2410     */
    2411     protected function getBoundary($boundary, $charSet, $contentType, $encoding)
    2412     {
    2413         $result = '';
    2414         if ($charSet == '') {
    2415             $charSet = $this->CharSet;
    2416         }
    2417         if ($contentType == '') {
    2418             $contentType = $this->ContentType;
    2419         }
    2420         if ($encoding == '') {
    2421             $encoding = $this->Encoding;
    2422         }
    2423         $result .= $this->textLine('--' . $boundary);
    2424         $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
    2425         $result .= $this->LE;
    2426         // RFC1341 part 5 says 7bit is assumed if not specified
    2427         if ($encoding != '7bit') {
    2428             $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
    2429         }
    2430         $result .= $this->LE;
     2407        /**
     2408        * Return the start of a message boundary.
     2409        * @access protected
     2410        * @param string $boundary
     2411        * @param string $charSet
     2412        * @param string $contentType
     2413        * @param string $encoding
     2414        * @return string
     2415        */
     2416        protected function getBoundary($boundary, $charSet, $contentType, $encoding)
     2417        {
     2418                $result = '';
     2419                if ($charSet == '') {
     2420                        $charSet = $this->CharSet;
     2421                }
     2422                if ($contentType == '') {
     2423                        $contentType = $this->ContentType;
     2424                }
     2425                if ($encoding == '') {
     2426                        $encoding = $this->Encoding;
     2427                }
     2428                $result .= $this->textLine('--' . $boundary);
     2429                $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
     2430                $result .= $this->LE;
     2431                // RFC1341 part 5 says 7bit is assumed if not specified
     2432                if ($encoding != '7bit') {
     2433                        $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
     2434                }
     2435                $result .= $this->LE;
    24312436
    2432         return $result;
    2433     }
     2437                return $result;
     2438        }
    24342439
    2435     /**
    2436     * Return the end of a message boundary.
    2437     * @access protected
    2438     * @param string $boundary
    2439     * @return string
    2440     */
    2441     protected function endBoundary($boundary)
    2442     {
    2443         return $this->LE . '--' . $boundary . '--' . $this->LE;
    2444     }
     2440        /**
     2441        * Return the end of a message boundary.
     2442        * @access protected
     2443        * @param string $boundary
     2444        * @return string
     2445        */
     2446        protected function endBoundary($boundary)
     2447        {
     2448                return $this->LE . '--' . $boundary . '--' . $this->LE;
     2449        }
    24452450
    2446     /**
    2447     * Set the message type.
    2448     * PHPMailer only supports some preset message types, not arbitrary MIME structures.
    2449     * @access protected
    2450     * @return void
    2451     */
    2452     protected function setMessageType()
    2453     {
    2454         $type = array();
    2455         if ($this->alternativeExists()) {
    2456             $type[] = 'alt';
    2457         }
    2458         if ($this->inlineImageExists()) {
    2459             $type[] = 'inline';
    2460         }
    2461         if ($this->attachmentExists()) {
    2462             $type[] = 'attach';
    2463         }
    2464         $this->message_type = implode('_', $type);
    2465         if ($this->message_type == '') {
    2466             //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
    2467             $this->message_type = 'plain';
    2468         }
    2469     }
     2451        /**
     2452        * Set the message type.
     2453        * PHPMailer only supports some preset message types, not arbitrary MIME structures.
     2454        * @access protected
     2455        * @return void
     2456        */
     2457        protected function setMessageType()
     2458        {
     2459                $type = array();
     2460                if ($this->alternativeExists()) {
     2461                        $type[] = 'alt';
     2462                }
     2463                if ($this->inlineImageExists()) {
     2464                        $type[] = 'inline';
     2465                }
     2466                if ($this->attachmentExists()) {
     2467                        $type[] = 'attach';
     2468                }
     2469                $this->message_type = implode('_', $type);
     2470                if ($this->message_type == '') {
     2471                        //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
     2472                        $this->message_type = 'plain';
     2473                }
     2474        }
    24702475
    2471     /**
    2472     * Format a header line.
    2473     * @access public
    2474     * @param string $name
    2475     * @param string $value
    2476     * @return string
    2477     */
    2478     public function headerLine($name, $value)
    2479     {
    2480         return $name . ': ' . $value . $this->LE;
    2481     }
     2476        /**
     2477        * Format a header line.
     2478        * @access public
     2479        * @param string $name
     2480        * @param string $value
     2481        * @return string
     2482        */
     2483        public function headerLine($name, $value)
     2484        {
     2485                return $name . ': ' . $value . $this->LE;
     2486        }
    24822487
    2483     /**
    2484     * Return a formatted mail line.
    2485     * @access public
    2486     * @param string $value
    2487     * @return string
    2488     */
    2489     public function textLine($value)
    2490     {
    2491         return $value . $this->LE;
    2492     }
     2488        /**
     2489        * Return a formatted mail line.
     2490        * @access public
     2491        * @param string $value
     2492        * @return string
     2493        */
     2494        public function textLine($value)
     2495        {
     2496                return $value . $this->LE;
     2497        }
    24932498
    2494     /**
    2495     * Add an attachment from a path on the filesystem.
    2496     * Never use a user-supplied path to a file!
    2497     * Returns false if the file could not be found or read.
    2498     * @param string $path Path to the attachment.
    2499     * @param string $name Overrides the attachment name.
    2500     * @param string $encoding File encoding (see $Encoding).
    2501     * @param string $type File extension (MIME) type.
    2502     * @param string $disposition Disposition to use
    2503     * @throws phpmailerException
    2504     * @return boolean
    2505     */
    2506     public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
    2507     {
    2508         try {
    2509             if (!@is_file($path)) {
    2510                 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
    2511             }
     2499        /**
     2500        * Add an attachment from a path on the filesystem.
     2501        * Never use a user-supplied path to a file!
     2502        * Returns false if the file could not be found or read.
     2503        * @param string $path Path to the attachment.
     2504        * @param string $name Overrides the attachment name.
     2505        * @param string $encoding File encoding (see $Encoding).
     2506        * @param string $type File extension (MIME) type.
     2507        * @param string $disposition Disposition to use
     2508        * @throws phpmailerException
     2509        * @return boolean
     2510        */
     2511        public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
     2512        {
     2513                try {
     2514                        if (!@is_file($path)) {
     2515                                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
     2516                        }
    25122517
    2513             // If a MIME type is not specified, try to work it out from the file name
    2514             if ($type == '') {
    2515                 $type = self::filenameToType($path);
    2516             }
     2518                        // If a MIME type is not specified, try to work it out from the file name
     2519                        if ($type == '') {
     2520                                $type = self::filenameToType($path);
     2521                        }
    25172522
    2518             $filename = basename($path);
    2519             if ($name == '') {
    2520                 $name = $filename;
    2521             }
     2523                        $filename = basename($path);
     2524                        if ($name == '') {
     2525                                $name = $filename;
     2526                        }
    25222527
    2523             $this->attachment[] = array(
    2524                 0 => $path,
    2525                 1 => $filename,
    2526                 2 => $name,
    2527                 3 => $encoding,
    2528                 4 => $type,
    2529                 5 => false, // isStringAttachment
    2530                 6 => $disposition,
    2531                 7 => 0
    2532             );
     2528                        $this->attachment[] = array(
     2529                                0 => $path,
     2530                                1 => $filename,
     2531                                2 => $name,
     2532                                3 => $encoding,
     2533                                4 => $type,
     2534                                5 => false, // isStringAttachment
     2535                                6 => $disposition,
     2536                                7 => 0
     2537                        );
    25332538
    2534         } catch (phpmailerException $exc) {
    2535             $this->setError($exc->getMessage());
    2536             $this->edebug($exc->getMessage());
    2537             if ($this->exceptions) {
    2538                 throw $exc;
    2539             }
    2540             return false;
    2541         }
    2542         return true;
    2543     }
     2539                } catch (phpmailerException $exc) {
     2540                        $this->setError($exc->getMessage());
     2541                        $this->edebug($exc->getMessage());
     2542                        if ($this->exceptions) {
     2543                                throw $exc;
     2544                        }
     2545                        return false;
     2546                }
     2547                return true;
     2548        }
    25442549
    2545     /**
    2546     * Return the array of attachments.
    2547     * @return array
    2548     */
    2549     public function getAttachments()
    2550     {
    2551         return $this->attachment;
    2552     }
     2550        /**
     2551        * Return the array of attachments.
     2552        * @return array
     2553        */
     2554        public function getAttachments()
     2555        {
     2556                return $this->attachment;
     2557        }
    25532558
    2554     /**
    2555     * Attach all file, string, and binary attachments to the message.
    2556     * Returns an empty string on failure.
    2557     * @access protected
    2558     * @param string $disposition_type
    2559     * @param string $boundary
    2560     * @return string
    2561     */
    2562     protected function attachAll($disposition_type, $boundary)
    2563     {
    2564         // Return text of body
    2565         $mime = array();
    2566         $cidUniq = array();
    2567         $incl = array();
     2559        /**
     2560        * Attach all file, string, and binary attachments to the message.
     2561        * Returns an empty string on failure.
     2562        * @access protected
     2563        * @param string $disposition_type
     2564        * @param string $boundary
     2565        * @return string
     2566        */
     2567        protected function attachAll($disposition_type, $boundary)
     2568        {
     2569                // Return text of body
     2570                $mime = array();
     2571                $cidUniq = array();
     2572                $incl = array();
    25682573
    2569         // Add all attachments
    2570         foreach ($this->attachment as $attachment) {
    2571             // Check if it is a valid disposition_filter
    2572             if ($attachment[6] == $disposition_type) {
    2573                 // Check for string attachment
    2574                 $string = '';
    2575                 $path = '';
    2576                 $bString = $attachment[5];
    2577                 if ($bString) {
    2578                     $string = $attachment[0];
    2579                 } else {
    2580                     $path = $attachment[0];
    2581                 }
     2574                // Add all attachments
     2575                foreach ($this->attachment as $attachment) {
     2576                        // Check if it is a valid disposition_filter
     2577                        if ($attachment[6] == $disposition_type) {
     2578                                // Check for string attachment
     2579                                $string = '';
     2580                                $path = '';
     2581                                $bString = $attachment[5];
     2582                                if ($bString) {
     2583                                        $string = $attachment[0];
     2584                                } else {
     2585                                        $path = $attachment[0];
     2586                                }
    25822587
    2583                 $inclhash = md5(serialize($attachment));
    2584                 if (in_array($inclhash, $incl)) {
    2585                     continue;
    2586                 }
    2587                 $incl[] = $inclhash;
    2588                 $name = $attachment[2];
    2589                 $encoding = $attachment[3];
    2590                 $type = $attachment[4];
    2591                 $disposition = $attachment[6];
    2592                 $cid = $attachment[7];
    2593                 if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
    2594                     continue;
    2595                 }
    2596                 $cidUniq[$cid] = true;
     2588                                $inclhash = md5(serialize($attachment));
     2589                                if (in_array($inclhash, $incl)) {
     2590                                        continue;
     2591                                }
     2592                                $incl[] = $inclhash;
     2593                                $name = $attachment[2];
     2594                                $encoding = $attachment[3];
     2595                                $type = $attachment[4];
     2596                                $disposition = $attachment[6];
     2597                                $cid = $attachment[7];
     2598                                if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
     2599                                        continue;
     2600                                }
     2601                                $cidUniq[$cid] = true;
    25972602
    2598                 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
    2599                 //Only include a filename property if we have one
    2600                 if (!empty($name)) {
    2601                     $mime[] = sprintf(
    2602                         'Content-Type: %s; name="%s"%s',
    2603                         $type,
    2604                         $this->encodeHeader($this->secureHeader($name)),
    2605                         $this->LE
    2606                     );
    2607                 } else {
    2608                     $mime[] = sprintf(
    2609                         'Content-Type: %s%s',
    2610                         $type,
    2611                         $this->LE
    2612                     );
    2613                 }
    2614                 // RFC1341 part 5 says 7bit is assumed if not specified
    2615                 if ($encoding != '7bit') {
    2616                     $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
    2617                 }
     2603                                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
     2604                                //Only include a filename property if we have one
     2605                                if (!empty($name)) {
     2606                                        $mime[] = sprintf(
     2607                                                'Content-Type: %s; name="%s"%s',
     2608                                                $type,
     2609                                                $this->encodeHeader($this->secureHeader($name)),
     2610                                                $this->LE
     2611                                        );
     2612                                } else {
     2613                                        $mime[] = sprintf(
     2614                                                'Content-Type: %s%s',
     2615                                                $type,
     2616                                                $this->LE
     2617                                        );
     2618                                }
     2619                                // RFC1341 part 5 says 7bit is assumed if not specified
     2620                                if ($encoding != '7bit') {
     2621                                        $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
     2622                                }
    26182623
    2619                 if ($disposition == 'inline') {
    2620                     $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
    2621                 }
     2624                                if ($disposition == 'inline') {
     2625                                        $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
     2626                                }
    26222627
    2623                 // If a filename contains any of these chars, it should be quoted,
    2624                 // but not otherwise: RFC2183 & RFC2045 5.1
    2625                 // Fixes a warning in IETF's msglint MIME checker
    2626                 // Allow for bypassing the Content-Disposition header totally
    2627                 if (!(empty($disposition))) {
    2628                     $encoded_name = $this->encodeHeader($this->secureHeader($name));
    2629                     if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
    2630                         $mime[] = sprintf(
    2631                             'Content-Disposition: %s; filename="%s"%s',
    2632                             $disposition,
    2633                             $encoded_name,
    2634                             $this->LE . $this->LE
    2635                         );
    2636                     } else {
    2637                         if (!empty($encoded_name)) {
    2638                             $mime[] = sprintf(
    2639                                 'Content-Disposition: %s; filename=%s%s',
    2640                                 $disposition,
    2641                                 $encoded_name,
    2642