Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

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