class.phpmailer.php 136 KB
Newer Older
1
2
<?php
/**
Aaron Wells's avatar
Aaron Wells committed
3
 * PHPMailer - PHP email creation and transport class.
4
 * PHP Version 5
5
 * @package PHPMailer
6
7
 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
Aaron Wells's avatar
Aaron Wells committed
8
9
10
 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
 * @author Brent R. Matzelle (original founder)
11
 * @copyright 2012 - 2014 Marcus Bointon
Aaron Wells's avatar
Aaron Wells committed
12
 * @copyright 2010 - 2012 Jim Jagielski
13
14
 * @copyright 2004 - 2009 Andy Prevost
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
Aaron Wells's avatar
Aaron Wells committed
15
16
17
 * @note This program is distributed in the hope that it will be useful - WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
18
19
20
 */

/**
Aaron Wells's avatar
Aaron Wells committed
21
22
 * PHPMailer - PHP email creation and transport class.
 * @package PHPMailer
23
 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
Aaron Wells's avatar
Aaron Wells committed
24
25
26
 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
 * @author Brent R. Matzelle (original founder)
27
 */
Aaron Wells's avatar
Aaron Wells committed
28
29
30
31
class PHPMailer
{
    /**
     * The PHPMailer Version number.
32
     * @var string
Aaron Wells's avatar
Aaron Wells committed
33
     */
34
    public $Version = '5.2.14';
Aaron Wells's avatar
Aaron Wells committed
35
36
37

    /**
     * Email priority.
38
39
40
     * Options: null (default), 1 = High, 3 = Normal, 5 = low.
     * When null, the header is not set at all.
     * @var integer
Aaron Wells's avatar
Aaron Wells committed
41
     */
42
    public $Priority = null;
Aaron Wells's avatar
Aaron Wells committed
43
44
45

    /**
     * The character set of the message.
46
     * @var string
Aaron Wells's avatar
Aaron Wells committed
47
48
49
50
51
     */
    public $CharSet = 'iso-8859-1';

    /**
     * The MIME Content-type of the message.
52
     * @var string
Aaron Wells's avatar
Aaron Wells committed
53
54
55
56
57
58
     */
    public $ContentType = 'text/plain';

    /**
     * The message encoding.
     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
59
     * @var string
Aaron Wells's avatar
Aaron Wells committed
60
61
62
63
64
     */
    public $Encoding = '8bit';

    /**
     * Holds the most recent mailer error message.
65
     * @var string
Aaron Wells's avatar
Aaron Wells committed
66
67
68
69
70
     */
    public $ErrorInfo = '';

    /**
     * The From email address for the message.
71
     * @var string
Aaron Wells's avatar
Aaron Wells committed
72
73
74
75
76
     */
    public $From = 'root@localhost';

    /**
     * The From name of the message.
77
     * @var string
Aaron Wells's avatar
Aaron Wells committed
78
79
80
81
82
83
     */
    public $FromName = 'Root User';

    /**
     * The Sender email (Return-Path) of the message.
     * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
84
     * @var string
Aaron Wells's avatar
Aaron Wells committed
85
86
87
88
89
90
     */
    public $Sender = '';

    /**
     * The Return-Path of the message.
     * If empty, it will be set to either From or Sender.
91
     * @var string
92
93
94
     * @deprecated Email senders should never set a return-path header;
     * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
     * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
Aaron Wells's avatar
Aaron Wells committed
95
96
97
98
99
     */
    public $ReturnPath = '';

    /**
     * The Subject of the message.
100
     * @var string
Aaron Wells's avatar
Aaron Wells committed
101
102
103
104
105
106
     */
    public $Subject = '';

    /**
     * An HTML or plain text message body.
     * If HTML then call isHTML(true).
107
     * @var string
Aaron Wells's avatar
Aaron Wells committed
108
109
110
111
112
113
114
115
     */
    public $Body = '';

    /**
     * The plain-text message body.
     * This body can be read by mail clients that do not have HTML email
     * capability such as mutt & Eudora.
     * Clients that can read HTML will view the normal Body.
116
     * @var string
Aaron Wells's avatar
Aaron Wells committed
117
118
119
120
121
122
123
124
125
     */
    public $AltBody = '';

    /**
     * An iCal message part body.
     * Only supported in simple alt or alt_inline message types
     * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
     * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
     * @link http://kigkonsult.se/iCalcreator/
126
     * @var string
Aaron Wells's avatar
Aaron Wells committed
127
128
129
130
131
132
     */
    public $Ical = '';

    /**
     * The complete compiled MIME message body.
     * @access protected
133
     * @var string
Aaron Wells's avatar
Aaron Wells committed
134
135
136
137
138
     */
    protected $MIMEBody = '';

    /**
     * The complete compiled MIME message headers.
139
     * @var string
Aaron Wells's avatar
Aaron Wells committed
140
141
142
143
144
145
     * @access protected
     */
    protected $MIMEHeader = '';

    /**
     * Extra headers that createHeader() doesn't fold in.
146
     * @var string
Aaron Wells's avatar
Aaron Wells committed
147
148
149
150
151
152
     * @access protected
     */
    protected $mailHeader = '';

    /**
     * Word-wrap the message body to this number of chars.
153
154
     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
     * @var integer
Aaron Wells's avatar
Aaron Wells committed
155
156
157
158
159
160
     */
    public $WordWrap = 0;

    /**
     * Which method to use to send mail.
     * Options: "mail", "sendmail", or "smtp".
161
     * @var string
Aaron Wells's avatar
Aaron Wells committed
162
163
164
165
166
     */
    public $Mailer = 'mail';

    /**
     * The path to the sendmail program.
167
     * @var string
Aaron Wells's avatar
Aaron Wells committed
168
169
170
171
172
173
     */
    public $Sendmail = '/usr/sbin/sendmail';

    /**
     * Whether mail() uses a fully sendmail-compatible MTA.
     * One which supports sendmail's "-oi -f" options.
174
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
175
176
177
178
179
180
     */
    public $UseSendmailOptions = true;

    /**
     * Path to PHPMailer plugins.
     * Useful if the SMTP class is not in the PHP include path.
181
     * @var string
Aaron Wells's avatar
Aaron Wells committed
182
183
184
185
186
     * @deprecated Should not be needed now there is an autoloader.
     */
    public $PluginDir = '';

    /**
187
188
     * The email address that a reading confirmation should be sent to, also known as read receipt.
     * @var string
Aaron Wells's avatar
Aaron Wells committed
189
190
191
192
     */
    public $ConfirmReadingTo = '';

    /**
193
194
195
196
197
     * The hostname to use in the Message-ID header and as default HELO string.
     * If empty, PHPMailer attempts to find one with, in order,
     * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
     * 'localhost.localdomain'.
     * @var string
Aaron Wells's avatar
Aaron Wells committed
198
199
200
201
     */
    public $Hostname = '';

    /**
202
     * An ID to be used in the Message-ID header.
Aaron Wells's avatar
Aaron Wells committed
203
     * If empty, a unique id will be generated.
204
     * @var string
Aaron Wells's avatar
Aaron Wells committed
205
206
207
208
209
210
     */
    public $MessageID = '';

    /**
     * The message Date to be used in the Date header.
     * If empty, the current date will be added.
211
     * @var string
Aaron Wells's avatar
Aaron Wells committed
212
213
214
215
216
217
218
219
220
     */
    public $MessageDate = '';

    /**
     * SMTP hosts.
     * Either a single hostname or multiple semicolon-delimited hostnames.
     * You can also specify a different port
     * for each host by using this format: [hostname:port]
     * (e.g. "smtp1.example.com:25;smtp2.example.com").
221
222
     * You can also specify encryption type, for example:
     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
Aaron Wells's avatar
Aaron Wells committed
223
     * Hosts will be tried in order.
224
     * @var string
Aaron Wells's avatar
Aaron Wells committed
225
226
227
228
229
     */
    public $Host = 'localhost';

    /**
     * The default SMTP server port.
230
     * @var integer
231
     * @TODO Why is this needed when the SMTP class takes care of it?
Aaron Wells's avatar
Aaron Wells committed
232
233
234
235
236
     */
    public $Port = 25;

    /**
     * The SMTP HELO of the message.
237
238
239
     * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
     * one with the same method described above for $Hostname.
     * @var string
Aaron Wells's avatar
Aaron Wells committed
240
241
242
243
244
     * @see PHPMailer::$Hostname
     */
    public $Helo = '';

    /**
245
246
247
     * What kind of encryption to use on the SMTP connection.
     * Options: '', 'ssl' or 'tls'
     * @var string
Aaron Wells's avatar
Aaron Wells committed
248
249
250
     */
    public $SMTPSecure = '';

251
252
253
254
255
256
257
258
    /**
     * Whether to enable TLS encryption automatically if a server supports it,
     * even if `SMTPSecure` is not set to 'tls'.
     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
     * @var boolean
     */
    public $SMTPAutoTLS = true;

Aaron Wells's avatar
Aaron Wells committed
259
260
261
    /**
     * Whether to use SMTP authentication.
     * Uses the Username and Password properties.
262
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
263
264
265
266
267
     * @see PHPMailer::$Username
     * @see PHPMailer::$Password
     */
    public $SMTPAuth = false;

268
269
270
271
272
273
    /**
     * Options array passed to stream_context_create when connecting via SMTP.
     * @var array
     */
    public $SMTPOptions = array();

Aaron Wells's avatar
Aaron Wells committed
274
275
    /**
     * SMTP username.
276
     * @var string
Aaron Wells's avatar
Aaron Wells committed
277
278
279
280
281
     */
    public $Username = '';

    /**
     * SMTP password.
282
     * @var string
Aaron Wells's avatar
Aaron Wells committed
283
284
285
286
287
288
     */
    public $Password = '';

    /**
     * SMTP auth type.
     * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
289
     * @var string
Aaron Wells's avatar
Aaron Wells committed
290
291
292
293
294
295
     */
    public $AuthType = '';

    /**
     * SMTP realm.
     * Used for NTLM auth
296
     * @var string
Aaron Wells's avatar
Aaron Wells committed
297
298
299
300
301
302
     */
    public $Realm = '';

    /**
     * SMTP workstation.
     * Used for NTLM auth
303
     * @var string
Aaron Wells's avatar
Aaron Wells committed
304
305
306
307
308
     */
    public $Workstation = '';

    /**
     * The SMTP server timeout in seconds.
309
310
     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     * @var integer
Aaron Wells's avatar
Aaron Wells committed
311
     */
312
    public $Timeout = 300;
Aaron Wells's avatar
Aaron Wells committed
313
314
315

    /**
     * SMTP class debug output mode.
316
317
318
319
320
321
322
     * Debug output level.
     * Options:
     * * `0` No output
     * * `1` Commands
     * * `2` Data and commands
     * * `3` As 2 plus connection status
     * * `4` Low-level data output
323
     * @var integer
Aaron Wells's avatar
Aaron Wells committed
324
325
326
327
328
     * @see SMTP::$do_debug
     */
    public $SMTPDebug = 0;

    /**
329
330
331
332
333
334
335
336
337
338
     * How to handle debug output.
     * Options:
     * * `echo` Output plain-text as-is, appropriate for CLI
     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
     * * `error_log` Output to error log as configured in php.ini
     *
     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
     * <code>
     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
     * </code>
339
     * @var string|callable
Aaron Wells's avatar
Aaron Wells committed
340
341
     * @see SMTP::$Debugoutput
     */
342
    public $Debugoutput = 'echo';
Aaron Wells's avatar
Aaron Wells committed
343
344
345
346
347

    /**
     * Whether to keep SMTP connection open after each message.
     * If this is set to true then to close the connection
     * requires an explicit call to smtpClose().
348
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
349
350
351
352
353
354
     */
    public $SMTPKeepAlive = false;

    /**
     * Whether to split multiple to addresses into multiple messages
     * or send them all in one message.
355
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
356
357
358
359
360
     */
    public $SingleTo = false;

    /**
     * Storage for addresses when SingleTo is enabled.
361
     * @var array
362
     * @TODO This should really not be public
Aaron Wells's avatar
Aaron Wells committed
363
364
365
366
367
368
     */
    public $SingleToArray = array();

    /**
     * Whether to generate VERP addresses on send.
     * Only applicable when sending via SMTP.
369
     * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
370
     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
371
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
372
373
374
375
376
     */
    public $do_verp = false;

    /**
     * Whether to allow sending messages with an empty body.
377
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
378
379
380
381
382
383
384
     */
    public $AllowEmpty = false;

    /**
     * The default line ending.
     * @note The default remains "\n". We force CRLF where we know
     *        it must be used via self::CRLF.
385
     * @var string
Aaron Wells's avatar
Aaron Wells committed
386
387
388
389
390
     */
    public $LE = "\n";

    /**
     * DKIM selector.
391
     * @var string
Aaron Wells's avatar
Aaron Wells committed
392
393
394
395
396
397
     */
    public $DKIM_selector = '';

    /**
     * DKIM Identity.
     * Usually the email address used as the source of the email
398
     * @var string
Aaron Wells's avatar
Aaron Wells committed
399
400
401
402
403
404
     */
    public $DKIM_identity = '';

    /**
     * DKIM passphrase.
     * Used if your key is encrypted.
405
     * @var string
Aaron Wells's avatar
Aaron Wells committed
406
407
408
409
410
411
     */
    public $DKIM_passphrase = '';

    /**
     * DKIM signing domain name.
     * @example 'example.com'
412
     * @var string
Aaron Wells's avatar
Aaron Wells committed
413
414
415
416
417
     */
    public $DKIM_domain = '';

    /**
     * DKIM private key file path.
418
     * @var string
Aaron Wells's avatar
Aaron Wells committed
419
420
421
422
423
424
425
426
427
     */
    public $DKIM_private = '';

    /**
     * Callback Action function name.
     *
     * The function that handles the result of the send email action.
     * It is called out by send() for each email sent.
     *
428
     * Value can be any php callable: http://www.php.net/is_callable
Aaron Wells's avatar
Aaron Wells committed
429
430
     *
     * Parameters:
431
     *   boolean $result        result of the send action
Aaron Wells's avatar
Aaron Wells committed
432
433
434
435
436
437
     *   string  $to            email address of the recipient
     *   string  $cc            cc email addresses
     *   string  $bcc           bcc email addresses
     *   string  $subject       the subject
     *   string  $body          the email body
     *   string  $from          email address of sender
438
     * @var string
Aaron Wells's avatar
Aaron Wells committed
439
440
441
442
     */
    public $action_function = '';

    /**
443
444
445
     * What to put in the X-Mailer header.
     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
     * @var string
Aaron Wells's avatar
Aaron Wells committed
446
447
448
449
450
     */
    public $XMailer = '';

    /**
     * An instance of the SMTP sender class.
451
     * @var SMTP
Aaron Wells's avatar
Aaron Wells committed
452
453
454
455
456
     * @access protected
     */
    protected $smtp = null;

    /**
457
458
     * The array of 'to' names and addresses.
     * @var array
Aaron Wells's avatar
Aaron Wells committed
459
460
461
462
463
     * @access protected
     */
    protected $to = array();

    /**
464
465
     * The array of 'cc' names and addresses.
     * @var array
Aaron Wells's avatar
Aaron Wells committed
466
467
468
469
470
     * @access protected
     */
    protected $cc = array();

    /**
471
472
     * The array of 'bcc' names and addresses.
     * @var array
Aaron Wells's avatar
Aaron Wells committed
473
474
475
476
477
478
     * @access protected
     */
    protected $bcc = array();

    /**
     * The array of reply-to names and addresses.
479
     * @var array
Aaron Wells's avatar
Aaron Wells committed
480
481
482
483
484
485
     * @access protected
     */
    protected $ReplyTo = array();

    /**
     * An array of all kinds of addresses.
486
487
     * Includes all of $to, $cc, $bcc
     * @var array
Aaron Wells's avatar
Aaron Wells committed
488
     * @access protected
489
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
Aaron Wells's avatar
Aaron Wells committed
490
491
492
     */
    protected $all_recipients = array();

493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
    /**
     * An array of names and addresses queued for validation.
     * In send(), valid and non duplicate entries are moved to $all_recipients
     * and one of $to, $cc, or $bcc.
     * This array is used only for addresses with IDN.
     * @var array
     * @access protected
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
     * @see PHPMailer::$all_recipients
     */
    protected $RecipientsQueue = array();

    /**
     * An array of reply-to names and addresses queued for validation.
     * In send(), valid and non duplicate entries are moved to $ReplyTo.
     * This array is used only for addresses with IDN.
     * @var array
     * @access protected
     * @see PHPMailer::$ReplyTo
     */
    protected $ReplyToQueue = array();

Aaron Wells's avatar
Aaron Wells committed
515
516
    /**
     * The array of attachments.
517
     * @var array
Aaron Wells's avatar
Aaron Wells committed
518
519
520
521
522
523
     * @access protected
     */
    protected $attachment = array();

    /**
     * The array of custom headers.
524
     * @var array
Aaron Wells's avatar
Aaron Wells committed
525
526
527
528
529
530
     * @access protected
     */
    protected $CustomHeader = array();

    /**
     * The most recent Message-ID (including angular brackets).
531
     * @var string
Aaron Wells's avatar
Aaron Wells committed
532
533
534
535
536
537
     * @access protected
     */
    protected $lastMessageID = '';

    /**
     * The message's MIME type.
538
     * @var string
Aaron Wells's avatar
Aaron Wells committed
539
540
541
542
543
544
     * @access protected
     */
    protected $message_type = '';

    /**
     * The array of MIME boundary strings.
545
     * @var array
Aaron Wells's avatar
Aaron Wells committed
546
547
548
549
550
551
     * @access protected
     */
    protected $boundary = array();

    /**
     * The array of available languages.
552
     * @var array
Aaron Wells's avatar
Aaron Wells committed
553
554
555
556
557
558
     * @access protected
     */
    protected $language = array();

    /**
     * The number of errors encountered.
559
     * @var integer
Aaron Wells's avatar
Aaron Wells committed
560
561
562
563
564
565
     * @access protected
     */
    protected $error_count = 0;

    /**
     * The S/MIME certificate file path.
566
     * @var string
Aaron Wells's avatar
Aaron Wells committed
567
568
569
570
571
572
     * @access protected
     */
    protected $sign_cert_file = '';

    /**
     * The S/MIME key file path.
573
     * @var string
Aaron Wells's avatar
Aaron Wells committed
574
575
576
577
     * @access protected
     */
    protected $sign_key_file = '';

578
579
580
581
582
583
584
    /**
     * The optional S/MIME extra certificates ("CA Chain") file path.
     * @var string
     * @access protected
     */
    protected $sign_extracerts_file = '';

Aaron Wells's avatar
Aaron Wells committed
585
586
587
    /**
     * The S/MIME password for the key.
     * Used only if the key is encrypted.
588
     * @var string
Aaron Wells's avatar
Aaron Wells committed
589
590
591
592
593
594
     * @access protected
     */
    protected $sign_key_pass = '';

    /**
     * Whether to throw exceptions for errors.
595
     * @var boolean
Aaron Wells's avatar
Aaron Wells committed
596
597
598
599
     * @access protected
     */
    protected $exceptions = false;

600
601
602
603
604
605
606
    /**
     * Unique ID used for message ID and boundaries.
     * @var string
     * @access protected
     */
    protected $uniqueid = '';

Aaron Wells's avatar
Aaron Wells committed
607
    /**
608
     * Error severity: message only, continue processing.
Aaron Wells's avatar
Aaron Wells committed
609
610
611
612
     */
    const STOP_MESSAGE = 0;

    /**
613
     * Error severity: message, likely ok to continue processing.
Aaron Wells's avatar
Aaron Wells committed
614
615
616
617
     */
    const STOP_CONTINUE = 1;

    /**
618
     * Error severity: message, plus full stop, critical error reached.
Aaron Wells's avatar
Aaron Wells committed
619
620
621
622
     */
    const STOP_CRITICAL = 2;

    /**
623
     * SMTP RFC standard line ending.
Aaron Wells's avatar
Aaron Wells committed
624
625
626
     */
    const CRLF = "\r\n";

627
628
629
630
631
632
    /**
     * The maximum line length allowed by RFC 2822 section 2.1.1
     * @var integer
     */
    const MAX_LINE_LENGTH = 998;

Aaron Wells's avatar
Aaron Wells committed
633
    /**
634
635
     * Constructor.
     * @param boolean $exceptions Should we throw external exceptions?
Aaron Wells's avatar
Aaron Wells committed
636
637
638
     */
    public function __construct($exceptions = false)
    {
639
        $this->exceptions = (boolean)$exceptions;
Aaron Wells's avatar
Aaron Wells committed
640
641
642
643
644
645
646
    }

    /**
     * Destructor.
     */
    public function __destruct()
    {
647
648
        //Close any open SMTP connection nicely
        if ($this->Mailer == 'smtp') {
Aaron Wells's avatar
Aaron Wells committed
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
            $this->smtpClose();
        }
    }

    /**
     * Call mail() in a safe_mode-aware fashion.
     * Also, unless sendmail_path points to sendmail (or something that
     * claims to be sendmail), don't pass params (not a perfect fix,
     * but it will do)
     * @param string $to To
     * @param string $subject Subject
     * @param string $body Message Body
     * @param string $header Additional Header(s)
     * @param string $params Params
     * @access private
664
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
665
666
667
     */
    private function mailPassthru($to, $subject, $body, $header, $params)
    {
668
669
670
671
672
673
        //Check overloading of mail function to avoid double-encoding
        if (ini_get('mbstring.func_overload') & 1) {
            $subject = $this->secureHeader($subject);
        } else {
            $subject = $this->encodeHeader($this->secureHeader($subject));
        }
Aaron Wells's avatar
Aaron Wells committed
674
        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
675
            $result = @mail($to, $subject, $body, $header);
Aaron Wells's avatar
Aaron Wells committed
676
        } else {
677
            $result = @mail($to, $subject, $body, $header, $params);
Aaron Wells's avatar
Aaron Wells committed
678
        }
679
        return $result;
Aaron Wells's avatar
Aaron Wells committed
680
681
682
683
    }

    /**
     * Output debugging info via user-defined method.
684
     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
Aaron Wells's avatar
Aaron Wells committed
685
686
687
688
689
690
     * @see PHPMailer::$Debugoutput
     * @see PHPMailer::$SMTPDebug
     * @param string $str
     */
    protected function edebug($str)
    {
691
692
693
        if ($this->SMTPDebug <= 0) {
            return;
        }
694
695
        //Avoid clash with built-in function names
        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
696
            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
Aaron Wells's avatar
Aaron Wells committed
697
698
699
700
            return;
        }
        switch ($this->Debugoutput) {
            case 'error_log':
701
                //Don't output, just log
Aaron Wells's avatar
Aaron Wells committed
702
703
704
                error_log($str);
                break;
            case 'html':
705
706
707
708
709
710
711
                //Cleans up output a bit for a better looking, HTML-safe output
                echo htmlentities(
                    preg_replace('/[\r\n]+/', '', $str),
                    ENT_QUOTES,
                    'UTF-8'
                )
                . "<br>\n";
Aaron Wells's avatar
Aaron Wells committed
712
713
714
                break;
            case 'echo':
            default:
715
716
717
718
719
720
721
                //Normalize line breaks
                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
                    "\n",
                    "\n                   \t                  ",
                    trim($str)
                ) . "\n";
Aaron Wells's avatar
Aaron Wells committed
722
723
724
725
726
        }
    }

    /**
     * Sets message type to HTML or plain.
727
     * @param boolean $isHtml True for HTML mode.
Aaron Wells's avatar
Aaron Wells committed
728
729
     * @return void
     */
730
    public function isHTML($isHtml = true)
Aaron Wells's avatar
Aaron Wells committed
731
    {
732
        if ($isHtml) {
Aaron Wells's avatar
Aaron Wells committed
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
            $this->ContentType = 'text/html';
        } else {
            $this->ContentType = 'text/plain';
        }
    }

    /**
     * Send messages using SMTP.
     * @return void
     */
    public function isSMTP()
    {
        $this->Mailer = 'smtp';
    }

    /**
     * Send messages using PHP's mail() function.
     * @return void
     */
    public function isMail()
    {
        $this->Mailer = 'mail';
    }

    /**
     * Send messages using $Sendmail.
     * @return void
     */
    public function isSendmail()
    {
763
764
765
766
767
768
        $ini_sendmail_path = ini_get('sendmail_path');

        if (!stristr($ini_sendmail_path, 'sendmail')) {
            $this->Sendmail = '/usr/sbin/sendmail';
        } else {
            $this->Sendmail = $ini_sendmail_path;
Aaron Wells's avatar
Aaron Wells committed
769
770
771
772
773
774
775
776
777
778
        }
        $this->Mailer = 'sendmail';
    }

    /**
     * Send messages using qmail.
     * @return void
     */
    public function isQmail()
    {
779
780
781
782
783
784
        $ini_sendmail_path = ini_get('sendmail_path');

        if (!stristr($ini_sendmail_path, 'qmail')) {
            $this->Sendmail = '/var/qmail/bin/qmail-inject';
        } else {
            $this->Sendmail = $ini_sendmail_path;
Aaron Wells's avatar
Aaron Wells committed
785
        }
786
        $this->Mailer = 'qmail';
Aaron Wells's avatar
Aaron Wells committed
787
788
789
790
    }

    /**
     * Add a "To" address.
791
     * @param string $address The email address to send to
Aaron Wells's avatar
Aaron Wells committed
792
     * @param string $name
793
     * @return boolean true on success, false if address already used or invalid in some way
Aaron Wells's avatar
Aaron Wells committed
794
795
796
     */
    public function addAddress($address, $name = '')
    {
797
        return $this->addOrEnqueueAnAddress('to', $address, $name);
Aaron Wells's avatar
Aaron Wells committed
798
799
800
801
802
    }

    /**
     * Add a "CC" address.
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
803
     * @param string $address The email address to send to
Aaron Wells's avatar
Aaron Wells committed
804
     * @param string $name
805
     * @return boolean true on success, false if address already used or invalid in some way
Aaron Wells's avatar
Aaron Wells committed
806
807
808
     */
    public function addCC($address, $name = '')
    {
809
        return $this->addOrEnqueueAnAddress('cc', $address, $name);
Aaron Wells's avatar
Aaron Wells committed
810
811
812
813
814
    }

    /**
     * Add a "BCC" address.
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
815
     * @param string $address The email address to send to
Aaron Wells's avatar
Aaron Wells committed
816
     * @param string $name
817
     * @return boolean true on success, false if address already used or invalid in some way
Aaron Wells's avatar
Aaron Wells committed
818
819
820
     */
    public function addBCC($address, $name = '')
    {
821
        return $this->addOrEnqueueAnAddress('bcc', $address, $name);
Aaron Wells's avatar
Aaron Wells committed
822
823
824
    }

    /**
825
826
     * Add a "Reply-To" address.
     * @param string $address The email address to reply to
Aaron Wells's avatar
Aaron Wells committed
827
     * @param string $name
828
     * @return boolean true on success, false if address already used or invalid in some way
Aaron Wells's avatar
Aaron Wells committed
829
830
831
     */
    public function addReplyTo($address, $name = '')
    {
832
        return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
Aaron Wells's avatar
Aaron Wells committed
833
834
835
    }

    /**
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
     * be modified after calling this function), addition of such addresses is delayed until send().
     * Addresses that have been added already return false, but do not throw exceptions.
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     * @param string $address The email address to send, resp. to reply to
     * @param string $name
     * @throws phpmailerException
     * @return boolean true on success, false if address already used or invalid in some way
     * @access protected
     */
    protected function addOrEnqueueAnAddress($kind, $address, $name)
    {
        $address = trim($address);
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
        if (($pos = strrpos($address, '@')) === false) {
            // At-sign is misssing.
            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
            $this->setError($error_message);
            $this->edebug($error_message);
            if ($this->exceptions) {
                throw new phpmailerException($error_message);
            }
            return false;
        }
        $params = array($kind, $address, $name);
        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
        if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
            if ($kind != 'Reply-To') {
                if (!array_key_exists($address, $this->RecipientsQueue)) {
                    $this->RecipientsQueue[$address] = $params;
                    return true;
                }
            } else {
                if (!array_key_exists($address, $this->ReplyToQueue)) {
                    $this->ReplyToQueue[$address] = $params;
                    return true;
                }
            }
            return false;
        }
        // Immediately add standard addresses without IDN.
        return call_user_func_array(array($this, 'addAnAddress'), $params);
    }

    /**
     * Add an address to one of the recipient arrays or to the ReplyTo array.
     * Addresses that have been added already return false, but do not throw exceptions.
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     * @param string $address The email address to send, resp. to reply to
Aaron Wells's avatar
Aaron Wells committed
886
887
     * @param string $name
     * @throws phpmailerException
888
     * @return boolean true on success, false if address already used or invalid in some way
Aaron Wells's avatar
Aaron Wells committed
889
890
891
892
     * @access protected
     */
    protected function addAnAddress($kind, $address, $name = '')
    {
893
894
895
896
        if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
            $error_message = $this->lang('Invalid recipient kind: ') . $kind;
            $this->setError($error_message);
            $this->edebug($error_message);
Aaron Wells's avatar
Aaron Wells committed
897
            if ($this->exceptions) {
898
                throw new phpmailerException($error_message);
Aaron Wells's avatar
Aaron Wells committed
899
900
901
902
            }
            return false;
        }
        if (!$this->validateAddress($address)) {
903
904
905
            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
            $this->setError($error_message);
            $this->edebug($error_message);
Aaron Wells's avatar
Aaron Wells committed
906
            if ($this->exceptions) {
907
                throw new phpmailerException($error_message);
Aaron Wells's avatar
Aaron Wells committed
908
909
910
911
            }
            return false;
        }
        if ($kind != 'Reply-To') {
912
            if (!array_key_exists(strtolower($address), $this->all_recipients)) {
Aaron Wells's avatar
Aaron Wells committed
913
914
915
916
917
918
919
920
921
922
923
924
925
                array_push($this->$kind, array($address, $name));
                $this->all_recipients[strtolower($address)] = true;
                return true;
            }
        } else {
            if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
                $this->ReplyTo[strtolower($address)] = array($address, $name);
                return true;
            }
        }
        return false;
    }

926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
    /**
     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
     * of the form "display name <address>" into an array of name/address pairs.
     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
     * Note that quotes in the name part are removed.
     * @param string $addrstr The address list string
     * @param bool $useimap Whether to use the IMAP extension to parse the list
     * @return array
     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
     */
    public function parseAddresses($addrstr, $useimap = true)
    {
        $addresses = array();
        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
            //Use this built-in parser if it's available
            $list = imap_rfc822_parse_adrlist($addrstr, '');
            foreach ($list as $address) {
                if ($address->host != '.SYNTAX-ERROR.') {
                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
                        $addresses[] = array(
                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
                            'address' => $address->mailbox . '@' . $address->host
                        );
                    }
                }
            }
        } else {
            //Use this simpler parser
            $list = explode(',', $addrstr);
            foreach ($list as $address) {
                $address = trim($address);
                //Is there a separate name part?
                if (strpos($address, '<') === false) {
                    //No separate name, just use the whole thing
                    if ($this->validateAddress($address)) {
                        $addresses[] = array(
                            'name' => '',
                            'address' => $address
                        );
                    }
                } else {
                    list($name, $email) = explode('<', $address);
                    $email = trim(str_replace('>', '', $email));
                    if ($this->validateAddress($email)) {
                        $addresses[] = array(
                            'name' => trim(str_replace(array('"', "'"), '', $name)),
                            'address' => $email
                        );
                    }
                }
            }
        }
        return $addresses;
    }

Aaron Wells's avatar
Aaron Wells committed
981
982
983
984
    /**
     * Set the From and FromName properties.
     * @param string $address
     * @param string $name
985
     * @param boolean $auto Whether to also set the Sender address, defaults to true
Aaron Wells's avatar
Aaron Wells committed
986
     * @throws phpmailerException
987
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
988
989
990
991
992
     */
    public function setFrom($address, $name = '', $auto = true)
    {
        $address = trim($address);
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
993
994
995
996
997
998
999
        // Don't validate now addresses with IDN. Will be done in send().
        if (($pos = strrpos($address, '@')) === false or
            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
            !$this->validateAddress($address)) {
            $error_message = $this->lang('invalid_address') . " (setFrom) $address";
            $this->setError($error_message);
            $this->edebug($error_message);
Aaron Wells's avatar
Aaron Wells committed
1000
            if ($this->exceptions) {
1001
                throw new phpmailerException($error_message);
Aaron Wells's avatar
Aaron Wells committed
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
            }
            return false;
        }
        $this->From = $address;
        $this->FromName = $name;
        if ($auto) {
            if (empty($this->Sender)) {
                $this->Sender = $address;
            }
        }
        return true;
    }

    /**
     * Return the Message-ID header of the last email.
     * Technically this is the value from the last time the headers were created,
     * but it's also the message ID of the last sent message except in
     * pathological cases.
     * @return string
     */
    public function getLastMessageID()
    {
        return $this->lastMessageID;
    }

    /**
     * Check that a string looks like an email address.
     * @param string $address The email address to check
     * @param string $patternselect A selector for the validation pattern to use :
1031
     * * `auto` Pick best pattern automatically;
1032
1033
     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
     * * `pcre` Use old PCRE implementation;
1034
     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1035
1036
1037
     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
     * * `noregex` Don't use a regex: super fast, really dumb.
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
1038
1039
1040
1041
1042
     * @static
     * @access public
     */
    public static function validateAddress($address, $patternselect = 'auto')
    {
1043
1044
1045
1046
        //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
        if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
            return false;
        }
1047
1048
1049
1050
1051
1052
        if (!$patternselect or $patternselect == 'auto') {
            //Check this constant first so it works when extension_loaded() is disabled by safe mode
            //Constant was added in PHP 5.2.4
            if (defined('PCRE_VERSION')) {
                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
Aaron Wells's avatar
Aaron Wells committed
1053
1054
1055
1056
                    $patternselect = 'pcre8';
                } else {
                    $patternselect = 'pcre';
                }
1057
1058
1059
            } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
                //Fall back to older PCRE
                $patternselect = 'pcre';
Aaron Wells's avatar
Aaron Wells committed
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
            } else {
                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
                    $patternselect = 'php';
                } else {
                    $patternselect = 'noregex';
                }
            }
        }
        switch ($patternselect) {
            case 'pcre8':
                /**
1072
                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
Aaron Wells's avatar
Aaron Wells committed
1073
1074
1075
1076
                 * @link http://squiloople.com/2009/12/20/email-address-validation/
                 * @copyright 2009-2010 Michael Rushton
                 * Feel free to use and redistribute this code. But please keep this copyright notice.
                 */
1077
                return (boolean)preg_match(
Aaron Wells's avatar
Aaron Wells committed
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
                    '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
                    '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
                    '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
                    '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
                    '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
                    '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
                    $address
                );
            case 'pcre':
                //An older regex that doesn't need a recent PCRE
1091
                return (boolean)preg_match(
Aaron Wells's avatar
Aaron Wells committed
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
                    '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
                    '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
                    '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
                    '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
                    '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
                    '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
                    '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
                    $address
                );
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
            case 'html5':
                /**
                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
                 */
                return (boolean)preg_match(
                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
                    $address
                );
Aaron Wells's avatar
Aaron Wells committed
1114
1115
1116
1117
1118
1119
            case 'noregex':
                //No PCRE! Do something _very_ approximate!
                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
                return (strlen($address) >= 3
                    and strpos($address, '@') >= 1
                    and strpos($address, '@') != strlen($address) - 1);
1120
1121
1122
            case 'php':
            default:
                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
Aaron Wells's avatar
Aaron Wells committed
1123
1124
1125
        }
    }

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
    /**
     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
     * "intl" and "mbstring" PHP extensions.
     * @return bool "true" if required functions for IDN support are present
     */
    public function idnSupported()
    {
        // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
        return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
    }

    /**
     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
     * This function silently returns unmodified address if:
     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
     * @see PHPMailer::$CharSet
     * @param string $address The email address to convert
     * @return string The encoded address in ASCII form
     */
    public function punyencodeAddress($address)
    {
        // Verify we have required functions, CharSet, and at-sign.
        if ($this->idnSupported() and
            !empty($this->CharSet) and
            ($pos = strrpos($address, '@')) !== false) {
            $domain = substr($address, ++$pos);
            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
            if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
                    idn_to_ascii($domain)) !== false) {
                    return substr($address, 0, $pos) . $punycode;
                }
            }
        }
        return $address;
    }

Aaron Wells's avatar
Aaron Wells committed
1168
1169
1170
1171
    /**
     * Create a message and send it.
     * Uses the sending method specified by $Mailer.
     * @throws phpmailerException
1172
     * @return boolean false on error - See the ErrorInfo property for details of the error.
Aaron Wells's avatar
Aaron Wells committed
1173
1174
1175
1176
1177
1178
1179
1180
     */
    public function send()
    {
        try {
            if (!$this->preSend()) {
                return false;
            }
            return $this->postSend();
1181
        } catch (phpmailerException $exc) {
Aaron Wells's avatar
Aaron Wells committed
1182
            $this->mailHeader = '';
1183
            $this->setError($exc->getMessage());
Aaron Wells's avatar
Aaron Wells committed
1184
            if ($this->exceptions) {
1185
                throw $exc;
Aaron Wells's avatar
Aaron Wells committed
1186
1187
1188
1189
1190
1191
1192
1193
            }
            return false;
        }
    }

    /**
     * Prepare a message for sending.
     * @throws phpmailerException
1194
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
1195
1196
1197
1198
     */
    public function preSend()
    {
        try {
1199
            $this->error_count = 0; // Reset errors
1200
            $this->mailHeader = '';
1201
1202
1203
1204
1205
1206

            // Dequeue recipient and Reply-To addresses with IDN
            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
                $params[1] = $this->punyencodeAddress($params[1]);
                call_user_func_array(array($this, 'addAnAddress'), $params);
            }
Aaron Wells's avatar
Aaron Wells committed
1207
1208
1209
1210
            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
            }

1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
            // Validate From, Sender, and ConfirmReadingTo addresses
            foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
                $this->$address_kind = trim($this->$address_kind);
                if (empty($this->$address_kind)) {
                    continue;
                }
                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
                if (!$this->validateAddress($this->$address_kind)) {
                    $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
                    $this->setError($error_message);
                    $this->edebug($error_message);
                    if ($this->exceptions) {
                        throw new phpmailerException($error_message);
                    }
                    return false;
                }
            }

Aaron Wells's avatar
Aaron Wells committed
1229
            // Set whether the message is multipart/alternative
1230
            if ($this->alternativeExists()) {
Aaron Wells's avatar
Aaron Wells committed
1231
1232
1233
1234
1235
1236
1237
1238
1239
                $this->ContentType = 'multipart/alternative';
            }

            $this->setMessageType();
            // Refuse to send an empty message unless we are specifically allowing it
            if (!$this->AllowEmpty and empty($this->Body)) {
                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
            }

1240
1241
            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
            $this->MIMEHeader = '';
Aaron Wells's avatar
Aaron Wells committed
1242
            $this->MIMEBody = $this->createBody();
1243
1244
1245
1246
            // createBody may have added some headers, so retain them
            $tempheaders = $this->MIMEHeader;
            $this->MIMEHeader = $this->createHeader();
            $this->MIMEHeader .= $tempheaders;
Aaron Wells's avatar
Aaron Wells committed
1247
1248
1249
1250
1251

            // To capture the complete message when using mail(), create
            // an extra header list which createHeader() doesn't fold in
            if ($this->Mailer == 'mail') {
                if (count($this->to) > 0) {
1252
                    $this->mailHeader .= $this->addrAppend('To', $this->to);
Aaron Wells's avatar
Aaron Wells committed
1253
                } else {
1254
                    $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
Aaron Wells's avatar
Aaron Wells committed
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
                }
                $this->mailHeader .= $this->headerLine(
                    'Subject',
                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
                );
            }

            // Sign with DKIM if enabled
            if (!empty($this->DKIM_domain)
                && !empty($this->DKIM_private)
                && !empty($this->DKIM_selector)
                && file_exists($this->DKIM_private)) {
                $header_dkim = $this->DKIM_Add(
                    $this->MIMEHeader . $this->mailHeader,
                    $this->encodeHeader($this->secureHeader($this->Subject)),
                    $this->MIMEBody
                );
                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
            }
            return true;
1276
1277
        } catch (phpmailerException $exc) {
            $this->setError($exc->getMessage());
Aaron Wells's avatar
Aaron Wells committed
1278
            if ($this->exceptions) {
1279
                throw $exc;
Aaron Wells's avatar
Aaron Wells committed
1280
1281
1282
1283
1284
1285
1286
1287
1288
            }
            return false;
        }
    }

    /**
     * Actually send a message.
     * Send the email via the selected mechanism
     * @throws phpmailerException
1289
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
1290
1291
1292
1293
1294
1295
1296
     */
    public function postSend()
    {
        try {
            // Choose the mailer and send through it
            switch ($this->Mailer) {
                case 'sendmail':
1297
                case 'qmail':
Aaron Wells's avatar
Aaron Wells committed
1298
1299
1300
1301
1302
1303
                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
                case 'smtp':
                    return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
                case 'mail':
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
                default:
1304
1305
1306
1307
1308
                    $sendMethod = $this->Mailer.'Send';
                    if (method_exists($this, $sendMethod)) {
                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
                    }

Aaron Wells's avatar
Aaron Wells committed
1309
1310
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
            }
1311
1312
1313
        } catch (phpmailerException $exc) {
            $this->setError($exc->getMessage());
            $this->edebug($exc->getMessage());
Aaron Wells's avatar
Aaron Wells committed
1314
            if ($this->exceptions) {
1315
                throw $exc;
Aaron Wells's avatar
Aaron Wells committed
1316
1317
            }
        }
1318
        return false;
Aaron Wells's avatar
Aaron Wells committed
1319
1320
1321
1322
1323
1324
1325
1326
1327
    }

    /**
     * Send mail using the $Sendmail program.
     * @param string $header The message headers
     * @param string $body The message body
     * @see PHPMailer::$Sendmail
     * @throws phpmailerException
     * @access protected
1328
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
1329
1330
1331
1332
     */
    protected function sendmailSend($header, $body)
    {
        if ($this->Sender != '') {
1333
1334
1335
1336
1337
            if ($this->Mailer == 'qmail') {
                $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
            } else {
                $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
            }
Aaron Wells's avatar
Aaron Wells committed
1338
        } else {
1339
1340
1341
1342
1343
            if ($this->Mailer == 'qmail') {
                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
            } else {
                $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
            }
Aaron Wells's avatar
Aaron Wells committed
1344
        }
1345
        if ($this->SingleTo) {
1346
            foreach ($this->SingleToArray as $toAddr) {
Aaron Wells's avatar
Aaron Wells committed
1347
1348
1349
                if (!@$mail = popen($sendmail, 'w')) {
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
                }
1350
                fputs($mail, 'To: ' . $toAddr . "\n");
Aaron Wells's avatar
Aaron Wells committed
1351
1352
1353
                fputs($mail, $header);
                fputs($mail, $body);
                $result = pclose($mail);
1354
1355
1356
1357
1358
1359
1360
1361
1362
                $this->doCallback(
                    ($result == 0),
                    array($toAddr),
                    $this->cc,
                    $this->bcc,
                    $this->Subject,
                    $body,
                    $this->From
                );
Aaron Wells's avatar
Aaron Wells committed
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
                if ($result != 0) {
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
                }
            }
        } else {
            if (!@$mail = popen($sendmail, 'w')) {
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
            }
            fputs($mail, $header);
            fputs($mail, $body);
            $result = pclose($mail);
1374
1375
1376
1377
1378
1379
1380
1381
1382
            $this->doCallback(
                ($result == 0),
                $this->to,
                $this->cc,
                $this->bcc,
                $this->Subject,
                $body,
                $this->From
            );
Aaron Wells's avatar
Aaron Wells committed
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
            if ($result != 0) {
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
            }
        }
        return true;
    }

    /**
     * Send mail using the PHP mail() function.
     * @param string $header The message headers
     * @param string $body The message body
     * @link http://www.php.net/manual/en/book.mail.php
     * @throws phpmailerException
     * @access protected
1397
     * @return boolean
Aaron Wells's avatar
Aaron Wells committed
1398
1399
1400
1401
     */
    protected function mailSend($header, $body)
    {
        $toArr = array();
1402
1403
        foreach ($this->to as $toaddr) {
            $toArr[] = $this->addrFormat($toaddr);
Aaron Wells's avatar
Aaron Wells committed
1404
1405
1406
1407
        }
        $to = implode(', ', $toArr);

        if (empty($this->Sender)) {
1408
            $params = ' ';
Aaron Wells's avatar
Aaron Wells committed
1409
        } else