MDL-57474 mailer: Make sure that our exlicit MessageID is trimmed
[moodle.git] / lib / phpmailer / class.phpmailer.php
CommitLineData
c1ccd3dd 1<?php
c1ccd3dd 2/**
29bf99fd 3 * PHPMailer - PHP email creation and transport class.
ccff58da 4 * PHP Version 5
706be214 5 * @package PHPMailer
ccff58da
MG
6 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
7 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
29bf99fd
PS
8 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
9 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
10 * @author Brent R. Matzelle (original founder)
ccff58da 11 * @copyright 2012 - 2014 Marcus Bointon
0747daba 12 * @copyright 2010 - 2012 Jim Jagielski
ed546836 13 * @copyright 2004 - 2009 Andy Prevost
ed546836 14 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
29bf99fd
PS
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.
c1ccd3dd 18 */
c1ccd3dd 19
ed546836 20/**
29bf99fd 21 * PHPMailer - PHP email creation and transport class.
29bf99fd 22 * @package PHPMailer
ccff58da 23 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
29bf99fd
PS
24 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
25 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
26 * @author Brent R. Matzelle (original founder)
ed546836 27 */
29bf99fd
PS
28class PHPMailer
29{
30 /**
31 * The PHPMailer Version number.
30f4e2d3 32 * @var string
29bf99fd 33 */
48dc4059 34 public $Version = '5.2.16';
29bf99fd
PS
35
36 /**
37 * Email priority.
ec9e2d04
CB
38 * Options: null (default), 1 = High, 3 = Normal, 5 = low.
39 * When null, the header is not set at all.
30f4e2d3 40 * @var integer
29bf99fd 41 */
ec9e2d04 42 public $Priority = null;
29bf99fd
PS
43
44 /**
45 * The character set of the message.
30f4e2d3 46 * @var string
29bf99fd
PS
47 */
48 public $CharSet = 'iso-8859-1';
49
50 /**
51 * The MIME Content-type of the message.
30f4e2d3 52 * @var string
29bf99fd
PS
53 */
54 public $ContentType = 'text/plain';
55
56 /**
57 * The message encoding.
58 * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
30f4e2d3 59 * @var string
29bf99fd
PS
60 */
61 public $Encoding = '8bit';
62
63 /**
64 * Holds the most recent mailer error message.
30f4e2d3 65 * @var string
29bf99fd
PS
66 */
67 public $ErrorInfo = '';
68
69 /**
70 * The From email address for the message.
30f4e2d3 71 * @var string
29bf99fd
PS
72 */
73 public $From = 'root@localhost';
74
75 /**
76 * The From name of the message.
30f4e2d3 77 * @var string
29bf99fd
PS
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.
30f4e2d3 84 * @var string
29bf99fd
PS
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.
30f4e2d3 91 * @var string
ccff58da
MG
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
29bf99fd
PS
95 */
96 public $ReturnPath = '';
97
98 /**
99 * The Subject of the message.
30f4e2d3 100 * @var string
29bf99fd
PS
101 */
102 public $Subject = '';
103
104 /**
105 * An HTML or plain text message body.
106 * If HTML then call isHTML(true).
30f4e2d3 107 * @var string
29bf99fd
PS
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.
30f4e2d3 116 * @var string
29bf99fd
PS
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/
30f4e2d3 126 * @var string
29bf99fd
PS
127 */
128 public $Ical = '';
129
130 /**
131 * The complete compiled MIME message body.
132 * @access protected
30f4e2d3 133 * @var string
29bf99fd
PS
134 */
135 protected $MIMEBody = '';
136
137 /**
138 * The complete compiled MIME message headers.
30f4e2d3 139 * @var string
29bf99fd
PS
140 * @access protected
141 */
142 protected $MIMEHeader = '';
143
144 /**
145 * Extra headers that createHeader() doesn't fold in.
30f4e2d3 146 * @var string
29bf99fd
PS
147 * @access protected
148 */
149 protected $mailHeader = '';
150
151 /**
152 * Word-wrap the message body to this number of chars.
ec9e2d04 153 * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
30f4e2d3 154 * @var integer
29bf99fd
PS
155 */
156 public $WordWrap = 0;
157
158 /**
159 * Which method to use to send mail.
160 * Options: "mail", "sendmail", or "smtp".
30f4e2d3 161 * @var string
29bf99fd
PS
162 */
163 public $Mailer = 'mail';
164
165 /**
166 * The path to the sendmail program.
30f4e2d3 167 * @var string
29bf99fd
PS
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.
30f4e2d3 174 * @var boolean
29bf99fd
PS
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.
30f4e2d3 181 * @var string
29bf99fd
PS
182 * @deprecated Should not be needed now there is an autoloader.
183 */
184 public $PluginDir = '';
185
186 /**
30f4e2d3
AG
187 * The email address that a reading confirmation should be sent to, also known as read receipt.
188 * @var string
29bf99fd
PS
189 */
190 public $ConfirmReadingTo = '';
191
192 /**
30f4e2d3
AG
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
29bf99fd
PS
198 */
199 public $Hostname = '';
200
201 /**
30f4e2d3 202 * An ID to be used in the Message-ID header.
29bf99fd 203 * If empty, a unique id will be generated.
30f4e2d3 204 * @var string
29bf99fd
PS
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.
30f4e2d3 211 * @var string
29bf99fd
PS
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").
ccff58da
MG
221 * You can also specify encryption type, for example:
222 * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
29bf99fd 223 * Hosts will be tried in order.
30f4e2d3 224 * @var string
29bf99fd
PS
225 */
226 public $Host = 'localhost';
227
228 /**
229 * The default SMTP server port.
30f4e2d3 230 * @var integer
ccff58da 231 * @TODO Why is this needed when the SMTP class takes care of it?
29bf99fd
PS
232 */
233 public $Port = 25;
234
235 /**
236 * The SMTP HELO of the message.
30f4e2d3
AG
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
29bf99fd
PS
240 * @see PHPMailer::$Hostname
241 */
242 public $Helo = '';
243
244 /**
ec9e2d04
CB
245 * What kind of encryption to use on the SMTP connection.
246 * Options: '', 'ssl' or 'tls'
30f4e2d3 247 * @var string
29bf99fd
PS
248 */
249 public $SMTPSecure = '';
250
ec9e2d04
CB
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.
30f4e2d3 255 * @var boolean
ec9e2d04
CB
256 */
257 public $SMTPAutoTLS = true;
258
29bf99fd
PS
259 /**
260 * Whether to use SMTP authentication.
261 * Uses the Username and Password properties.
30f4e2d3 262 * @var boolean
29bf99fd
PS
263 * @see PHPMailer::$Username
264 * @see PHPMailer::$Password
265 */
266 public $SMTPAuth = false;
267
ec9e2d04
CB
268 /**
269 * Options array passed to stream_context_create when connecting via SMTP.
30f4e2d3 270 * @var array
ec9e2d04
CB
271 */
272 public $SMTPOptions = array();
273
29bf99fd
PS
274 /**
275 * SMTP username.
30f4e2d3 276 * @var string
29bf99fd
PS
277 */
278 public $Username = '';
279
280 /**
281 * SMTP password.
30f4e2d3 282 * @var string
29bf99fd
PS
283 */
284 public $Password = '';
285
286 /**
287 * SMTP auth type.
48dc4059 288 * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified
30f4e2d3 289 * @var string
29bf99fd
PS
290 */
291 public $AuthType = '';
292
293 /**
294 * SMTP realm.
295 * Used for NTLM auth
30f4e2d3 296 * @var string
29bf99fd
PS
297 */
298 public $Realm = '';
299
300 /**
301 * SMTP workstation.
302 * Used for NTLM auth
30f4e2d3 303 * @var string
29bf99fd
PS
304 */
305 public $Workstation = '';
306
307 /**
308 * The SMTP server timeout in seconds.
ec9e2d04 309 * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
30f4e2d3 310 * @var integer
29bf99fd 311 */
ec9e2d04 312 public $Timeout = 300;
29bf99fd
PS
313
314 /**
315 * SMTP class debug output mode.
ccff58da
MG
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
30f4e2d3 323 * @var integer
29bf99fd
PS
324 * @see SMTP::$do_debug
325 */
326 public $SMTPDebug = 0;
327
328 /**
ccff58da
MG
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>
30f4e2d3 339 * @var string|callable
29bf99fd
PS
340 * @see SMTP::$Debugoutput
341 */
ccff58da 342 public $Debugoutput = 'echo';
29bf99fd
PS
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().
30f4e2d3 348 * @var boolean
29bf99fd
PS
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.
48dc4059 355 * Only supported in `mail` and `sendmail` transports, not in SMTP.
30f4e2d3 356 * @var boolean
29bf99fd
PS
357 */
358 public $SingleTo = false;
359
360 /**
361 * Storage for addresses when SingleTo is enabled.
30f4e2d3 362 * @var array
ccff58da 363 * @TODO This should really not be public
29bf99fd
PS
364 */
365 public $SingleToArray = array();
366
367 /**
368 * Whether to generate VERP addresses on send.
369 * Only applicable when sending via SMTP.
30f4e2d3 370 * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
ccff58da 371 * @link http://www.postfix.org/VERP_README.html Postfix VERP info
30f4e2d3 372 * @var boolean
29bf99fd
PS
373 */
374 public $do_verp = false;
375
376 /**
377 * Whether to allow sending messages with an empty body.
30f4e2d3 378 * @var boolean
29bf99fd
PS
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.
30f4e2d3 386 * @var string
29bf99fd
PS
387 */
388 public $LE = "\n";
389
390 /**
391 * DKIM selector.
30f4e2d3 392 * @var string
29bf99fd
PS
393 */
394 public $DKIM_selector = '';
395
396 /**
397 * DKIM Identity.
48dc4059 398 * Usually the email address used as the source of the email.
30f4e2d3 399 * @var string
29bf99fd
PS
400 */
401 public $DKIM_identity = '';
402
403 /**
404 * DKIM passphrase.
405 * Used if your key is encrypted.
30f4e2d3 406 * @var string
29bf99fd
PS
407 */
408 public $DKIM_passphrase = '';
409
410 /**
411 * DKIM signing domain name.
412 * @example 'example.com'
30f4e2d3 413 * @var string
29bf99fd
PS
414 */
415 public $DKIM_domain = '';
416
417 /**
418 * DKIM private key file path.
30f4e2d3 419 * @var string
29bf99fd
PS
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 *
ccff58da 429 * Value can be any php callable: http://www.php.net/is_callable
29bf99fd
PS
430 *
431 * Parameters:
ccff58da 432 * boolean $result result of the send action
29bf99fd
PS
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
30f4e2d3 439 * @var string
29bf99fd
PS
440 */
441 public $action_function = '';
442
443 /**
ec9e2d04
CB
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
30f4e2d3 446 * @var string
29bf99fd
PS
447 */
448 public $XMailer = '';
30f4e2d3 449
48dc4059
SL
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
29bf99fd
PS
459 /**
460 * An instance of the SMTP sender class.
30f4e2d3 461 * @var SMTP
29bf99fd
PS
462 * @access protected
463 */
464 protected $smtp = null;
465
466 /**
30f4e2d3
AG
467 * The array of 'to' names and addresses.
468 * @var array
29bf99fd
PS
469 * @access protected
470 */
471 protected $to = array();
472
473 /**
30f4e2d3
AG
474 * The array of 'cc' names and addresses.
475 * @var array
29bf99fd
PS
476 * @access protected
477 */
478 protected $cc = array();
479
480 /**
30f4e2d3
AG
481 * The array of 'bcc' names and addresses.
482 * @var array
29bf99fd
PS
483 * @access protected
484 */
485 protected $bcc = array();
486
487 /**
488 * The array of reply-to names and addresses.
30f4e2d3 489 * @var array
29bf99fd
PS
490 * @access protected
491 */
492 protected $ReplyTo = array();
493
494 /**
495 * An array of all kinds of addresses.
ec9e2d04 496 * Includes all of $to, $cc, $bcc
30f4e2d3 497 * @var array
29bf99fd 498 * @access protected
30f4e2d3 499 * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
29bf99fd
PS
500 */
501 protected $all_recipients = array();
502
30f4e2d3
AG
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
29bf99fd
PS
525 /**
526 * The array of attachments.
30f4e2d3 527 * @var array
29bf99fd
PS
528 * @access protected
529 */
530 protected $attachment = array();
531
532 /**
533 * The array of custom headers.
30f4e2d3 534 * @var array
29bf99fd
PS
535 * @access protected
536 */
537 protected $CustomHeader = array();
538
539 /**
540 * The most recent Message-ID (including angular brackets).
30f4e2d3 541 * @var string
29bf99fd
PS
542 * @access protected
543 */
544 protected $lastMessageID = '';
545
546 /**
547 * The message's MIME type.
30f4e2d3 548 * @var string
29bf99fd
PS
549 * @access protected
550 */
551 protected $message_type = '';
552
553 /**
554 * The array of MIME boundary strings.
30f4e2d3 555 * @var array
29bf99fd
PS
556 * @access protected
557 */
558 protected $boundary = array();
559
560 /**
561 * The array of available languages.
30f4e2d3 562 * @var array
29bf99fd
PS
563 * @access protected
564 */
565 protected $language = array();
566
567 /**
568 * The number of errors encountered.
30f4e2d3 569 * @var integer
29bf99fd
PS
570 * @access protected
571 */
572 protected $error_count = 0;
573
574 /**
575 * The S/MIME certificate file path.
30f4e2d3 576 * @var string
29bf99fd
PS
577 * @access protected
578 */
579 protected $sign_cert_file = '';
580
581 /**
582 * The S/MIME key file path.
30f4e2d3 583 * @var string
29bf99fd
PS
584 * @access protected
585 */
586 protected $sign_key_file = '';
587
ec9e2d04
CB
588 /**
589 * The optional S/MIME extra certificates ("CA Chain") file path.
30f4e2d3 590 * @var string
ec9e2d04
CB
591 * @access protected
592 */
593 protected $sign_extracerts_file = '';
594
29bf99fd
PS
595 /**
596 * The S/MIME password for the key.
597 * Used only if the key is encrypted.
30f4e2d3 598 * @var string
29bf99fd
PS
599 * @access protected
600 */
601 protected $sign_key_pass = '';
602
603 /**
604 * Whether to throw exceptions for errors.
30f4e2d3 605 * @var boolean
29bf99fd
PS
606 * @access protected
607 */
608 protected $exceptions = false;
609
ec9e2d04
CB
610 /**
611 * Unique ID used for message ID and boundaries.
30f4e2d3 612 * @var string
ec9e2d04
CB
613 * @access protected
614 */
615 protected $uniqueid = '';
616
29bf99fd 617 /**
ccff58da 618 * Error severity: message only, continue processing.
29bf99fd
PS
619 */
620 const STOP_MESSAGE = 0;
621
622 /**
ccff58da 623 * Error severity: message, likely ok to continue processing.
29bf99fd
PS
624 */
625 const STOP_CONTINUE = 1;
626
627 /**
ccff58da 628 * Error severity: message, plus full stop, critical error reached.
29bf99fd
PS
629 */
630 const STOP_CRITICAL = 2;
631
632 /**
ccff58da 633 * SMTP RFC standard line ending.
29bf99fd
PS
634 */
635 const CRLF = "\r\n";
636
ec9e2d04
CB
637 /**
638 * The maximum line length allowed by RFC 2822 section 2.1.1
30f4e2d3 639 * @var integer
ec9e2d04
CB
640 */
641 const MAX_LINE_LENGTH = 998;
642
29bf99fd 643 /**
ccff58da
MG
644 * Constructor.
645 * @param boolean $exceptions Should we throw external exceptions?
29bf99fd 646 */
48dc4059 647 public function __construct($exceptions = null)
29bf99fd 648 {
48dc4059
SL
649 if ($exceptions !== null) {
650 $this->exceptions = (boolean)$exceptions;
651 }
29bf99fd
PS
652 }
653
654 /**
655 * Destructor.
656 */
657 public function __destruct()
658 {
ec9e2d04 659 //Close any open SMTP connection nicely
48dc4059 660 $this->smtpClose();
29bf99fd
PS
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
ccff58da 674 * @return boolean
29bf99fd
PS
675 */
676 private function mailPassthru($to, $subject, $body, $header, $params)
677 {
ccff58da
MG
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 }
48dc4059
SL
684 //Can't use additional_parameters in safe_mode
685 //@link http://php.net/manual/en/function.mail.php
686 if (ini_get('safe_mode') or !$this->UseSendmailOptions) {
ccff58da 687 $result = @mail($to, $subject, $body, $header);
29bf99fd 688 } else {
ccff58da 689 $result = @mail($to, $subject, $body, $header, $params);
29bf99fd 690 }
ccff58da 691 return $result;
29bf99fd
PS
692 }
693
694 /**
695 * Output debugging info via user-defined method.
ccff58da 696 * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
29bf99fd
PS
697 * @see PHPMailer::$Debugoutput
698 * @see PHPMailer::$SMTPDebug
699 * @param string $str
700 */
701 protected function edebug($str)
702 {
ccff58da
MG
703 if ($this->SMTPDebug <= 0) {
704 return;
705 }
ec9e2d04
CB
706 //Avoid clash with built-in function names
707 if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
ccff58da 708 call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
29bf99fd
PS
709 return;
710 }
711 switch ($this->Debugoutput) {
712 case 'error_log':
ccff58da 713 //Don't output, just log
29bf99fd
PS
714 error_log($str);
715 break;
716 case 'html':
ccff58da
MG
717 //Cleans up output a bit for a better looking, HTML-safe output
718 echo htmlentities(
719 preg_replace('/[\r\n]+/', '', $str),
720 ENT_QUOTES,
721 'UTF-8'
722 )
723 . "<br>\n";
29bf99fd
PS
724 break;
725 case 'echo':
726 default:
ccff58da 727 //Normalize line breaks
48dc4059 728 $str = preg_replace('/\r\n?/ms', "\n", $str);
ccff58da
MG
729 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
730 "\n",
731 "\n \t ",
732 trim($str)
733 ) . "\n";
29bf99fd
PS
734 }
735 }
736
737 /**
738 * Sets message type to HTML or plain.
ccff58da 739 * @param boolean $isHtml True for HTML mode.
29bf99fd
PS
740 * @return void
741 */
ccff58da 742 public function isHTML($isHtml = true)
29bf99fd 743 {
ccff58da 744 if ($isHtml) {
29bf99fd
PS
745 $this->ContentType = 'text/html';
746 } else {
747 $this->ContentType = 'text/plain';
748 }
749 }
750
751 /**
752 * Send messages using SMTP.
753 * @return void
754 */
755 public function isSMTP()
756 {
757 $this->Mailer = 'smtp';
758 }
759
760 /**
761 * Send messages using PHP's mail() function.
762 * @return void
763 */
764 public function isMail()
765 {
766 $this->Mailer = 'mail';
767 }
768
769 /**
770 * Send messages using $Sendmail.
771 * @return void
772 */
773 public function isSendmail()
774 {
ccff58da
MG
775 $ini_sendmail_path = ini_get('sendmail_path');
776
777 if (!stristr($ini_sendmail_path, 'sendmail')) {
778 $this->Sendmail = '/usr/sbin/sendmail';
779 } else {
780 $this->Sendmail = $ini_sendmail_path;
29bf99fd
PS
781 }
782 $this->Mailer = 'sendmail';
783 }
784
785 /**
786 * Send messages using qmail.
787 * @return void
788 */
789 public function isQmail()
790 {
ccff58da
MG
791 $ini_sendmail_path = ini_get('sendmail_path');
792
793 if (!stristr($ini_sendmail_path, 'qmail')) {
794 $this->Sendmail = '/var/qmail/bin/qmail-inject';
795 } else {
796 $this->Sendmail = $ini_sendmail_path;
29bf99fd 797 }
ccff58da 798 $this->Mailer = 'qmail';
29bf99fd
PS
799 }
800
801 /**
802 * Add a "To" address.
30f4e2d3 803 * @param string $address The email address to send to
29bf99fd 804 * @param string $name
30f4e2d3 805 * @return boolean true on success, false if address already used or invalid in some way
29bf99fd
PS
806 */
807 public function addAddress($address, $name = '')
808 {
30f4e2d3 809 return $this->addOrEnqueueAnAddress('to', $address, $name);
29bf99fd
PS
810 }
811
812 /**
813 * Add a "CC" address.
814 * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
30f4e2d3 815 * @param string $address The email address to send to
29bf99fd 816 * @param string $name
30f4e2d3 817 * @return boolean true on success, false if address already used or invalid in some way
29bf99fd
PS
818 */
819 public function addCC($address, $name = '')
820 {
30f4e2d3 821 return $this->addOrEnqueueAnAddress('cc', $address, $name);
29bf99fd
PS
822 }
823
824 /**
825 * Add a "BCC" address.
826 * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
30f4e2d3 827 * @param string $address The email address to send to
29bf99fd 828 * @param string $name
30f4e2d3 829 * @return boolean true on success, false if address already used or invalid in some way
29bf99fd
PS
830 */
831 public function addBCC($address, $name = '')
832 {
30f4e2d3 833 return $this->addOrEnqueueAnAddress('bcc', $address, $name);
29bf99fd
PS
834 }
835
836 /**
30f4e2d3
AG
837 * Add a "Reply-To" address.
838 * @param string $address The email address to reply to
29bf99fd 839 * @param string $name
30f4e2d3 840 * @return boolean true on success, false if address already used or invalid in some way
29bf99fd
PS
841 */
842 public function addReplyTo($address, $name = '')
843 {
30f4e2d3 844 return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
29bf99fd
PS
845 }
846
847 /**
30f4e2d3
AG
848 * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
849 * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
850 * be modified after calling this function), addition of such addresses is delayed until send().
851 * Addresses that have been added already return false, but do not throw exceptions.
852 * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
853 * @param string $address The email address to send, resp. to reply to
854 * @param string $name
855 * @throws phpmailerException
856 * @return boolean true on success, false if address already used or invalid in some way
857 * @access protected
858 */
859 protected function addOrEnqueueAnAddress($kind, $address, $name)
860 {
861 $address = trim($address);
862 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
863 if (($pos = strrpos($address, '@')) === false) {
864 // At-sign is misssing.
48dc4059 865 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
30f4e2d3
AG
866 $this->setError($error_message);
867 $this->edebug($error_message);
868 if ($this->exceptions) {
869 throw new phpmailerException($error_message);
870 }
871 return false;
872 }
873 $params = array($kind, $address, $name);
874 // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
875 if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
876 if ($kind != 'Reply-To') {
877 if (!array_key_exists($address, $this->RecipientsQueue)) {
878 $this->RecipientsQueue[$address] = $params;
879 return true;
880 }
881 } else {
882 if (!array_key_exists($address, $this->ReplyToQueue)) {
883 $this->ReplyToQueue[$address] = $params;
884 return true;
885 }
886 }
887 return false;
888 }
889 // Immediately add standard addresses without IDN.
890 return call_user_func_array(array($this, 'addAnAddress'), $params);
891 }
892
893 /**
894 * Add an address to one of the recipient arrays or to the ReplyTo array.
895 * Addresses that have been added already return false, but do not throw exceptions.
896 * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
897 * @param string $address The email address to send, resp. to reply to
29bf99fd
PS
898 * @param string $name
899 * @throws phpmailerException
ccff58da 900 * @return boolean true on success, false if address already used or invalid in some way
29bf99fd
PS
901 * @access protected
902 */
903 protected function addAnAddress($kind, $address, $name = '')
904 {
30f4e2d3
AG
905 if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
906 $error_message = $this->lang('Invalid recipient kind: ') . $kind;
907 $this->setError($error_message);
908 $this->edebug($error_message);
29bf99fd 909 if ($this->exceptions) {
30f4e2d3 910 throw new phpmailerException($error_message);
29bf99fd 911 }
29bf99fd
PS
912 return false;
913 }
29bf99fd 914 if (!$this->validateAddress($address)) {
48dc4059 915 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
30f4e2d3
AG
916 $this->setError($error_message);
917 $this->edebug($error_message);
29bf99fd 918 if ($this->exceptions) {
30f4e2d3 919 throw new phpmailerException($error_message);
29bf99fd 920 }
29bf99fd
PS
921 return false;
922 }
923 if ($kind != 'Reply-To') {
30f4e2d3 924 if (!array_key_exists(strtolower($address), $this->all_recipients)) {
29bf99fd
PS
925 array_push($this->$kind, array($address, $name));
926 $this->all_recipients[strtolower($address)] = true;
927 return true;
928 }
929 } else {
930 if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
931 $this->ReplyTo[strtolower($address)] = array($address, $name);
932 return true;
933 }
934 }
ed546836 935 return false;
29bf99fd
PS
936 }
937
ec9e2d04
CB
938 /**
939 * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
940 * of the form "display name <address>" into an array of name/address pairs.
941 * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
942 * Note that quotes in the name part are removed.
943 * @param string $addrstr The address list string
944 * @param bool $useimap Whether to use the IMAP extension to parse the list
945 * @return array
946 * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
947 */
948 public function parseAddresses($addrstr, $useimap = true)
949 {
950 $addresses = array();
951 if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
952 //Use this built-in parser if it's available
953 $list = imap_rfc822_parse_adrlist($addrstr, '');
954 foreach ($list as $address) {
955 if ($address->host != '.SYNTAX-ERROR.') {
956 if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
957 $addresses[] = array(
958 'name' => (property_exists($address, 'personal') ? $address->personal : ''),
959 'address' => $address->mailbox . '@' . $address->host
960 );
961 }
962 }
963 }
964 } else {
965 //Use this simpler parser
966 $list = explode(',', $addrstr);
967 foreach ($list as $address) {
968 $address = trim($address);
969 //Is there a separate name part?
970 if (strpos($address, '<') === false) {
971 //No separate name, just use the whole thing
972 if ($this->validateAddress($address)) {
973 $addresses[] = array(
974 'name' => '',
975 'address' => $address
976 );
977 }
978 } else {
979 list($name, $email) = explode('<', $address);
980 $email = trim(str_replace('>', '', $email));
981 if ($this->validateAddress($email)) {
982 $addresses[] = array(
983 'name' => trim(str_replace(array('"', "'"), '', $name)),
984 'address' => $email
985 );
986 }
987 }
988 }
989 }
990 return $addresses;
991 }
992
29bf99fd
PS
993 /**
994 * Set the From and FromName properties.
995 * @param string $address
996 * @param string $name
ccff58da 997 * @param boolean $auto Whether to also set the Sender address, defaults to true
29bf99fd 998 * @throws phpmailerException
ccff58da 999 * @return boolean
29bf99fd
PS
1000 */
1001 public function setFrom($address, $name = '', $auto = true)
1002 {
1003 $address = trim($address);
1004 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
30f4e2d3
AG
1005 // Don't validate now addresses with IDN. Will be done in send().
1006 if (($pos = strrpos($address, '@')) === false or
1007 (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1008 !$this->validateAddress($address)) {
48dc4059 1009 $error_message = $this->lang('invalid_address') . " (setFrom) $address";
30f4e2d3
AG
1010 $this->setError($error_message);
1011 $this->edebug($error_message);
29bf99fd 1012 if ($this->exceptions) {
30f4e2d3 1013 throw new phpmailerException($error_message);
29bf99fd 1014 }
29bf99fd
PS
1015 return false;
1016 }
1017 $this->From = $address;
1018 $this->FromName = $name;
1019 if ($auto) {
1020 if (empty($this->Sender)) {
1021 $this->Sender = $address;
1022 }
1023 }
ed546836 1024 return true;
29bf99fd
PS
1025 }
1026
1027 /**
1028 * Return the Message-ID header of the last email.
1029 * Technically this is the value from the last time the headers were created,
1030 * but it's also the message ID of the last sent message except in
1031 * pathological cases.
1032 * @return string
1033 */
1034 public function getLastMessageID()
1035 {
1036 return $this->lastMessageID;
1037 }
1038
1039 /**
1040 * Check that a string looks like an email address.
1041 * @param string $address The email address to check
48dc4059 1042 * @param string|callable $patternselect A selector for the validation pattern to use :
30f4e2d3 1043 * * `auto` Pick best pattern automatically;
ccff58da
MG
1044 * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1045 * * `pcre` Use old PCRE implementation;
30f4e2d3 1046 * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
ccff58da
MG
1047 * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1048 * * `noregex` Don't use a regex: super fast, really dumb.
48dc4059
SL
1049 * Alternatively you may pass in a callable to inject your own validator, for example:
1050 * PHPMailer::validateAddress('user@example.com', function($address) {
1051 * return (strpos($address, '@') !== false);
1052 * });
1053 * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
ccff58da 1054 * @return boolean
29bf99fd
PS
1055 * @static
1056 * @access public
1057 */
48dc4059 1058 public static function validateAddress($address, $patternselect = null)
29bf99fd 1059 {
48dc4059
SL
1060 if (is_null($patternselect)) {
1061 $patternselect = self::$validator;
1062 }
1063 if (is_callable($patternselect)) {
1064 return call_user_func($patternselect, $address);
1065 }
30f4e2d3
AG
1066 //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1067 if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1068 return false;
1069 }
ccff58da
MG
1070 if (!$patternselect or $patternselect == 'auto') {
1071 //Check this constant first so it works when extension_loaded() is disabled by safe mode
1072 //Constant was added in PHP 5.2.4
1073 if (defined('PCRE_VERSION')) {
1074 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1075 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
29bf99fd
PS
1076 $patternselect = 'pcre8';
1077 } else {
1078 $patternselect = 'pcre';
1079 }
ccff58da
MG
1080 } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1081 //Fall back to older PCRE
1082 $patternselect = 'pcre';
29bf99fd
PS
1083 } else {
1084 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1085 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1086 $patternselect = 'php';
1087 } else {
1088 $patternselect = 'noregex';
1089 }
1090 }
1091 }
1092 switch ($patternselect) {
1093 case 'pcre8':
1094 /**
ccff58da 1095 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
29bf99fd
PS
1096 * @link http://squiloople.com/2009/12/20/email-address-validation/
1097 * @copyright 2009-2010 Michael Rushton
1098 * Feel free to use and redistribute this code. But please keep this copyright notice.
1099 */
ccff58da 1100 return (boolean)preg_match(
29bf99fd
PS
1101 '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1102 '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1103 '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1104 '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1105 '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1106 '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1107 '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1108 '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1109 '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1110 $address
1111 );
29bf99fd
PS
1112 case 'pcre':
1113 //An older regex that doesn't need a recent PCRE
ccff58da 1114 return (boolean)preg_match(
29bf99fd
PS
1115 '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1116 '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1117 '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1118 '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1119 '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1120 '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1121 '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1122 '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1123 '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1124 '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1125 $address
1126 );
ccff58da
MG
1127 case 'html5':
1128 /**
1129 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1130 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1131 */
1132 return (boolean)preg_match(
1133 '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1134 '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1135 $address
1136 );
29bf99fd
PS
1137 case 'noregex':
1138 //No PCRE! Do something _very_ approximate!
1139 //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1140 return (strlen($address) >= 3
1141 and strpos($address, '@') >= 1
1142 and strpos($address, '@') != strlen($address) - 1);
ccff58da
MG
1143 case 'php':
1144 default:
1145 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
29bf99fd
PS
1146 }
1147 }
1148
30f4e2d3
AG
1149 /**
1150 * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1151 * "intl" and "mbstring" PHP extensions.
1152 * @return bool "true" if required functions for IDN support are present
1153 */
1154 public function idnSupported()
1155 {
1156 // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1157 return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1158 }
1159
1160 /**
1161 * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1162 * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1163 * This function silently returns unmodified address if:
1164 * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1165 * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1166 * or fails for any reason (e.g. domain has characters not allowed in an IDN)
1167 * @see PHPMailer::$CharSet
1168 * @param string $address The email address to convert
1169 * @return string The encoded address in ASCII form
1170 */
1171 public function punyencodeAddress($address)
1172 {
1173 // Verify we have required functions, CharSet, and at-sign.
1174 if ($this->idnSupported() and
1175 !empty($this->CharSet) and
1176 ($pos = strrpos($address, '@')) !== false) {
1177 $domain = substr($address, ++$pos);
1178 // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1179 if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1180 $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1181 if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1182 idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1183 idn_to_ascii($domain)) !== false) {
1184 return substr($address, 0, $pos) . $punycode;
1185 }
1186 }
1187 }
1188 return $address;
1189 }
1190
29bf99fd
PS
1191 /**
1192 * Create a message and send it.
1193 * Uses the sending method specified by $Mailer.
29bf99fd 1194 * @throws phpmailerException
ccff58da 1195 * @return boolean false on error - See the ErrorInfo property for details of the error.
29bf99fd
PS
1196 */
1197 public function send()
1198 {
1199 try {
1200 if (!$this->preSend()) {
1201 return false;
1202 }
1203 return $this->postSend();
ccff58da 1204 } catch (phpmailerException $exc) {
29bf99fd 1205 $this->mailHeader = '';
ccff58da 1206 $this->setError($exc->getMessage());
29bf99fd 1207 if ($this->exceptions) {
ccff58da 1208 throw $exc;
29bf99fd
PS
1209 }
1210 return false;
1211 }
1212 }
1213
1214 /**
1215 * Prepare a message for sending.
1216 * @throws phpmailerException
ccff58da 1217 * @return boolean
29bf99fd
PS
1218 */
1219 public function preSend()
1220 {
1221 try {
30f4e2d3 1222 $this->error_count = 0; // Reset errors
ccff58da 1223 $this->mailHeader = '';
30f4e2d3
AG
1224
1225 // Dequeue recipient and Reply-To addresses with IDN
1226 foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1227 $params[1] = $this->punyencodeAddress($params[1]);
1228 call_user_func_array(array($this, 'addAnAddress'), $params);
1229 }
29bf99fd
PS
1230 if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1231 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1232 }
1233
30f4e2d3
AG
1234 // Validate From, Sender, and ConfirmReadingTo addresses
1235 foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1236 $this->$address_kind = trim($this->$address_kind);
1237 if (empty($this->$address_kind)) {
1238 continue;
1239 }
1240 $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1241 if (!$this->validateAddress($this->$address_kind)) {
48dc4059 1242 $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
30f4e2d3
AG
1243 $this->setError($error_message);
1244 $this->edebug($error_message);
1245 if ($this->exceptions) {
1246 throw new phpmailerException($error_message);
1247 }
1248 return false;
1249 }
1250 }
1251
29bf99fd 1252 // Set whether the message is multipart/alternative
48dc4059 1253 if ($this->alternativeExists()) {
29bf99fd
PS
1254 $this->ContentType = 'multipart/alternative';
1255 }
1256
29bf99fd
PS
1257 $this->setMessageType();
1258 // Refuse to send an empty message unless we are specifically allowing it
1259 if (!$this->AllowEmpty and empty($this->Body)) {
1260 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1261 }
1262
ec9e2d04
CB
1263 // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1264 $this->MIMEHeader = '';
29bf99fd 1265 $this->MIMEBody = $this->createBody();
ec9e2d04
CB
1266 // createBody may have added some headers, so retain them
1267 $tempheaders = $this->MIMEHeader;
1268 $this->MIMEHeader = $this->createHeader();
1269 $this->MIMEHeader .= $tempheaders;
29bf99fd
PS
1270
1271 // To capture the complete message when using mail(), create
1272 // an extra header list which createHeader() doesn't fold in
1273 if ($this->Mailer == 'mail') {
1274 if (count($this->to) > 0) {
ccff58da 1275 $this->mailHeader .= $this->addrAppend('To', $this->to);
29bf99fd 1276 } else {
ccff58da 1277 $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
29bf99fd
PS
1278 }
1279 $this->mailHeader .= $this->headerLine(
1280 'Subject',
1281 $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1282 );
1283 }
1284
1285 // Sign with DKIM if enabled
1286 if (!empty($this->DKIM_domain)
1287 && !empty($this->DKIM_private)
1288 && !empty($this->DKIM_selector)
29bf99fd
PS
1289 && file_exists($this->DKIM_private)) {
1290 $header_dkim = $this->DKIM_Add(
1291 $this->MIMEHeader . $this->mailHeader,
1292 $this->encodeHeader($this->secureHeader($this->Subject)),
1293 $this->MIMEBody
1294 );
1295 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1296 str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1297 }
1298 return true;
ccff58da
MG
1299 } catch (phpmailerException $exc) {
1300 $this->setError($exc->getMessage());
29bf99fd 1301 if ($this->exceptions) {
ccff58da 1302 throw $exc;
29bf99fd
PS
1303 }
1304 return false;
1305 }
1306 }
1307
1308 /**
1309 * Actually send a message.
1310 * Send the email via the selected mechanism
1311 * @throws phpmailerException
ccff58da 1312 * @return boolean
29bf99fd
PS
1313 */
1314 public function postSend()
1315 {
1316 try {
1317 // Choose the mailer and send through it
1318 switch ($this->Mailer) {
1319 case 'sendmail':
ccff58da 1320 case 'qmail':
29bf99fd
PS
1321 return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1322 case 'smtp':
1323 return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1324 case 'mail':
1325 return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1326 default:
ccff58da
MG
1327 $sendMethod = $this->Mailer.'Send';
1328 if (method_exists($this, $sendMethod)) {
1329 return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1330 }
1331
29bf99fd
PS
1332 return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1333 }
ccff58da
MG
1334 } catch (phpmailerException $exc) {
1335 $this->setError($exc->getMessage());
1336 $this->edebug($exc->getMessage());
29bf99fd 1337 if ($this->exceptions) {
ccff58da 1338 throw $exc;
29bf99fd 1339 }
29bf99fd
PS
1340 }
1341 return false;
1342 }
1343
1344 /**
1345 * Send mail using the $Sendmail program.
1346 * @param string $header The message headers
1347 * @param string $body The message body
1348 * @see PHPMailer::$Sendmail
1349 * @throws phpmailerException
1350 * @access protected
ccff58da 1351 * @return boolean
29bf99fd
PS
1352 */
1353 protected function sendmailSend($header, $body)
1354 {
1355 if ($this->Sender != '') {
ccff58da
MG
1356 if ($this->Mailer == 'qmail') {
1357 $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1358 } else {
1359 $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1360 }
0747daba 1361 } else {
ccff58da
MG
1362 if ($this->Mailer == 'qmail') {
1363 $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1364 } else {
1365 $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1366 }
29bf99fd 1367 }
ec9e2d04 1368 if ($this->SingleTo) {
ccff58da 1369 foreach ($this->SingleToArray as $toAddr) {
29bf99fd
PS
1370 if (!@$mail = popen($sendmail, 'w')) {
1371 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1372 }
ccff58da 1373 fputs($mail, 'To: ' . $toAddr . "\n");
29bf99fd
PS
1374 fputs($mail, $header);
1375 fputs($mail, $body);
1376 $result = pclose($mail);
ccff58da
MG
1377 $this->doCallback(
1378 ($result == 0),
1379 array($toAddr),
1380 $this->cc,
1381 $this->bcc,
1382 $this->Subject,
1383 $body,
1384 $this->From
1385 );
29bf99fd
PS
1386 if ($result != 0) {
1387 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1388 }
1389 }
ed546836 1390 } else {
29bf99fd
PS
1391 if (!@$mail = popen($sendmail, 'w')) {
1392 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1393 }
1394 fputs($mail, $header);
1395 fputs($mail, $body);
1396 $result = pclose($mail);
30f4e2d3
AG
1397 $this->doCallback(
1398 ($result == 0),
1399 $this->to,
1400 $this->cc,
1401 $this->bcc,
1402 $this->Subject,
1403 $body,
1404 $this->From
1405 );
29bf99fd
PS
1406 if ($result != 0) {
1407 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1408 }
c1ccd3dd 1409 }
29bf99fd
PS
1410 return true;
1411 }
c1ccd3dd 1412
29bf99fd
PS
1413 /**
1414 * Send mail using the PHP mail() function.
1415 * @param string $header The message headers
1416 * @param string $body The message body
1417 * @link http://www.php.net/manual/en/book.mail.php
1418 * @throws phpmailerException
1419 * @access protected
ccff58da 1420 * @return boolean
29bf99fd
PS
1421 */
1422 protected function mailSend($header, $body)
1423 {
1424 $toArr = array();
ccff58da
MG
1425 foreach ($this->to as $toaddr) {
1426 $toArr[] = $this->addrFormat($toaddr);
29bf99fd
PS
1427 }
1428 $to = implode(', ', $toArr);
c1ccd3dd 1429
48dc4059
SL
1430 $params = null;
1431 //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
1432 if (!empty($this->Sender)) {
ccff58da 1433 $params = sprintf('-f%s', $this->Sender);
29bf99fd
PS
1434 }
1435 if ($this->Sender != '' and !ini_get('safe_mode')) {
1436 $old_from = ini_get('sendmail_from');
1437 ini_set('sendmail_from', $this->Sender);
1438 }
ccff58da 1439 $result = false;
48dc4059 1440 if ($this->SingleTo and count($toArr) > 1) {
ccff58da
MG
1441 foreach ($toArr as $toAddr) {
1442 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1443 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
29bf99fd
PS
1444 }
1445 } else {
ccff58da
MG
1446 $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1447 $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
29bf99fd
PS
1448 }
1449 if (isset($old_from)) {
1450 ini_set('sendmail_from', $old_from);
1451 }
ccff58da 1452 if (!$result) {
29bf99fd
PS
1453 throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1454 }
1455 return true;
1456 }
ed546836 1457
29bf99fd
PS
1458 /**
1459 * Get an instance to use for SMTP operations.
1460 * Override this function to load your own SMTP implementation
1461 * @return SMTP
1462 */
1463 public function getSMTPInstance()
1464 {
1465 if (!is_object($this->smtp)) {
1466 $this->smtp = new SMTP;
1467 }
1468 return $this->smtp;
1469 }
1470
1471 /**
1472 * Send mail via SMTP.
1473 * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1474 * Uses the PHPMailerSMTP class by default.
1475 * @see PHPMailer::getSMTPInstance() to use a different class.
1476 * @param string $header The message headers
1477 * @param string $body The message body
1478 * @throws phpmailerException
1479 * @uses SMTP
1480 * @access protected
ccff58da 1481 * @return boolean
29bf99fd
PS
1482 */
1483 protected function smtpSend($header, $body)
1484 {
1485 $bad_rcpt = array();
ec9e2d04 1486 if (!$this->smtpConnect($this->SMTPOptions)) {
29bf99fd
PS
1487 throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1488 }
ec9e2d04
CB
1489 if ('' == $this->Sender) {
1490 $smtp_from = $this->From;
1491 } else {
1492 $smtp_from = $this->Sender;
1493 }
29bf99fd
PS
1494 if (!$this->smtp->mail($smtp_from)) {
1495 $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1496 throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1497 }
ed546836 1498
ccff58da 1499 // Attempt to send to all recipients
ec9e2d04
CB
1500 foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1501 foreach ($togroup as $to) {
1502 if (!$this->smtp->recipient($to[0])) {
1503 $error = $this->smtp->getError();
1504 $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1505 $isSent = false;
1506 } else {
1507 $isSent = true;
1508 }
1509 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
29bf99fd 1510 }
29bf99fd 1511 }
c1ccd3dd 1512
ccff58da
MG
1513 // Only send the DATA command if we have viable recipients
1514 if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
29bf99fd
PS
1515 throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1516 }
ec9e2d04 1517 if ($this->SMTPKeepAlive) {
29bf99fd
PS
1518 $this->smtp->reset();
1519 } else {
1520 $this->smtp->quit();
1521 $this->smtp->close();
1522 }
ec9e2d04
CB
1523 //Create error message for any bad addresses
1524 if (count($bad_rcpt) > 0) {
1525 $errstr = '';
1526 foreach ($bad_rcpt as $bad) {
1527 $errstr .= $bad['to'] . ': ' . $bad['error'];
1528 }
ccff58da 1529 throw new phpmailerException(
ec9e2d04 1530 $this->lang('recipients_failed') . $errstr,
ccff58da
MG
1531 self::STOP_CONTINUE
1532 );
1533 }
29bf99fd
PS
1534 return true;
1535 }
c1ccd3dd 1536
29bf99fd
PS
1537 /**
1538 * Initiate a connection to an SMTP server.
1539 * Returns false if the operation failed.
1540 * @param array $options An array of options compatible with stream_context_create()
1541 * @uses SMTP
1542 * @access public
1543 * @throws phpmailerException
ccff58da 1544 * @return boolean
29bf99fd 1545 */
48dc4059 1546 public function smtpConnect($options = null)
29bf99fd
PS
1547 {
1548 if (is_null($this->smtp)) {
1549 $this->smtp = $this->getSMTPInstance();
1550 }
30f4e2d3 1551
48dc4059
SL
1552 //If no options are provided, use whatever is set in the instance
1553 if (is_null($options)) {
1554 $options = $this->SMTPOptions;
1555 }
1556
ccff58da 1557 // Already connected?
29bf99fd
PS
1558 if ($this->smtp->connected()) {
1559 return true;
1560 }
1561
1562 $this->smtp->setTimeout($this->Timeout);
1563 $this->smtp->setDebugLevel($this->SMTPDebug);
1564 $this->smtp->setDebugOutput($this->Debugoutput);
1565 $this->smtp->setVerp($this->do_verp);
29bf99fd
PS
1566 $hosts = explode(';', $this->Host);
1567 $lastexception = null;
1568
1569 foreach ($hosts as $hostentry) {
1570 $hostinfo = array();
ccff58da
MG
1571 if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1572 // Not a valid host entry
1573 continue;
1574 }
1575 // $hostinfo[2]: optional ssl or tls prefix
1576 // $hostinfo[3]: the hostname
1577 // $hostinfo[4]: optional port number
1578 // The host string prefix can temporarily override the current setting for SMTPSecure
1579 // If it's not specified, the default value is used
1580 $prefix = '';
ec9e2d04 1581 $secure = $this->SMTPSecure;
ccff58da 1582 $tls = ($this->SMTPSecure == 'tls');
ec9e2d04 1583 if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
ccff58da 1584 $prefix = 'ssl://';
ec9e2d04
CB
1585 $tls = false; // Can't have SSL and TLS at the same time
1586 $secure = 'ssl';
ccff58da
MG
1587 } elseif ($hostinfo[2] == 'tls') {
1588 $tls = true;
1589 // tls doesn't use a prefix
ec9e2d04
CB
1590 $secure = 'tls';
1591 }
1592 //Do we need the OpenSSL extension?
1593 $sslext = defined('OPENSSL_ALGO_SHA1');
1594 if ('tls' === $secure or 'ssl' === $secure) {
1595 //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1596 if (!$sslext) {
1597 throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1598 }
ccff58da
MG
1599 }
1600 $host = $hostinfo[3];
29bf99fd 1601 $port = $this->Port;
ccff58da
MG
1602 $tport = (integer)$hostinfo[4];
1603 if ($tport > 0 and $tport < 65536) {
1604 $port = $tport;
ed546836 1605 }
ccff58da 1606 if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
29bf99fd
PS
1607 try {
1608 if ($this->Helo) {
1609 $hello = $this->Helo;
1610 } else {
1611 $hello = $this->serverHostname();
1612 }
1613 $this->smtp->hello($hello);
ec9e2d04
CB
1614 //Automatically enable TLS encryption if:
1615 // * it's not disabled
1616 // * we have openssl extension
1617 // * we are not already using SSL
1618 // * the server offers STARTTLS
1619 if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1620 $tls = true;
1621 }
29bf99fd
PS
1622 if ($tls) {
1623 if (!$this->smtp->startTLS()) {
1624 throw new phpmailerException($this->lang('connect_host'));
1625 }
48dc4059 1626 // We must resend EHLO after TLS negotiation
29bf99fd
PS
1627 $this->smtp->hello($hello);
1628 }
1629 if ($this->SMTPAuth) {
1630 if (!$this->smtp->authenticate(
30f4e2d3
AG
1631 $this->Username,
1632 $this->Password,
1633 $this->AuthType,
1634 $this->Realm,
29bf99fd
PS
1635 $this->Workstation
1636 )
1637 ) {
1638 throw new phpmailerException($this->lang('authenticate'));
1639 }
1640 }
1641 return true;
ccff58da
MG
1642 } catch (phpmailerException $exc) {
1643 $lastexception = $exc;
ec9e2d04 1644 $this->edebug($exc->getMessage());
ccff58da 1645 // We must have connected, but then failed TLS or Auth, so close connection nicely
29bf99fd
PS
1646 $this->smtp->quit();
1647 }
1648 }
1649 }
ccff58da 1650 // If we get here, all connection attempts have failed, so close connection hard
29bf99fd 1651 $this->smtp->close();
ccff58da 1652 // As we've caught all exceptions, just report whatever the last one was
29bf99fd
PS
1653 if ($this->exceptions and !is_null($lastexception)) {
1654 throw $lastexception;
1655 }
1656 return false;
1657 }
1658
1659 /**
1660 * Close the active SMTP session if one exists.
1661 * @return void
1662 */
1663 public function smtpClose()
1664 {
48dc4059 1665 if (is_a($this->smtp, 'SMTP')) {
29bf99fd
PS
1666 if ($this->smtp->connected()) {
1667 $this->smtp->quit();
1668 $this->smtp->close();
706be214 1669 }
29bf99fd
PS
1670 }
1671 }
1672
1673 /**
1674 * Set the language for error messages.
1675 * Returns false if it cannot load the language file.
1676 * The default language is English.
1677 * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1678 * @param string $lang_path Path to the language file directory, with trailing separator (slash)
ccff58da 1679 * @return boolean
29bf99fd
PS
1680 * @access public
1681 */
ccff58da 1682 public function setLanguage($langcode = 'en', $lang_path = '')
29bf99fd 1683 {
ccff58da 1684 // Define full set of translatable strings in English
29bf99fd
PS
1685 $PHPMAILER_LANG = array(
1686 'authenticate' => 'SMTP Error: Could not authenticate.',
1687 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1688 'data_not_accepted' => 'SMTP Error: data not accepted.',
1689 'empty_message' => 'Message body empty',
1690 'encoding' => 'Unknown encoding: ',
1691 'execute' => 'Could not execute: ',
1692 'file_access' => 'Could not access file: ',
1693 'file_open' => 'File Error: Could not open file: ',
1694 'from_failed' => 'The following From address failed: ',
1695 'instantiate' => 'Could not instantiate mail function.',
30f4e2d3 1696 'invalid_address' => 'Invalid address: ',
29bf99fd
PS
1697 'mailer_not_supported' => ' mailer is not supported.',
1698 'provide_address' => 'You must provide at least one recipient email address.',
1699 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1700 'signing' => 'Signing Error: ',
1701 'smtp_connect_failed' => 'SMTP connect() failed.',
1702 'smtp_error' => 'SMTP server error: ',
ec9e2d04
CB
1703 'variable_set' => 'Cannot set or reset variable: ',
1704 'extension_missing' => 'Extension missing: '
29bf99fd 1705 );
ccff58da
MG
1706 if (empty($lang_path)) {
1707 // Calculate an absolute path so it can work if CWD is not here
1708 $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1709 }
1710 $foundlang = true;
1711 $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
ec9e2d04
CB
1712 // There is no English translation file
1713 if ($langcode != 'en') {
ccff58da
MG
1714 // Make sure language file path is readable
1715 if (!is_readable($lang_file)) {
1716 $foundlang = false;
1717 } else {
1718 // Overwrite language-specific strings.
ec9e2d04 1719 // This way we'll never have missing translation keys.
ccff58da
MG
1720 $foundlang = include $lang_file;
1721 }
29bf99fd
PS
1722 }
1723 $this->language = $PHPMAILER_LANG;
ec9e2d04 1724 return (boolean)$foundlang; // Returns false if language not found
29bf99fd
PS
1725 }
1726
1727 /**
1728 * Get the array of strings for the current language.
1729 * @return array
1730 */
1731 public function getTranslations()
1732 {
1733 return $this->language;
1734 }
1735
1736 /**
1737 * Create recipient headers.
1738 * @access public
1739 * @param string $type
1740 * @param array $addr An array of recipient,
1741 * where each recipient is a 2-element indexed array with element 0 containing an address
1742 * and element 1 containing a name, like:
1743 * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1744 * @return string
1745 */
1746 public function addrAppend($type, $addr)
1747 {
1748 $addresses = array();
ccff58da
MG
1749 foreach ($addr as $address) {
1750 $addresses[] = $this->addrFormat($address);
29bf99fd
PS
1751 }
1752 return $type . ': ' . implode(', ', $addresses) . $this->LE;
1753 }
1754
1755 /**
1756 * Format an address for use in a message header.
1757 * @access public
1758 * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1759 * like array('joe@example.com', 'Joe User')
1760 * @return string
1761 */
1762 public function addrFormat($addr)
1763 {
1764 if (empty($addr[1])) { // No name provided
1765 return $this->secureHeader($addr[0]);
1766 } else {
ccff58da 1767 return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
29bf99fd 1768 $addr[0]
ccff58da 1769 ) . '>';
29bf99fd
PS
1770 }
1771 }
1772
1773 /**
1774 * Word-wrap message.
1775 * For use with mailers that do not automatically perform wrapping
1776 * and for quoted-printable encoded messages.
1777 * Original written by philippe.
1778 * @param string $message The message to wrap
1779 * @param integer $length The line length to wrap to
ccff58da 1780 * @param boolean $qp_mode Whether to run in Quoted-Printable mode
29bf99fd
PS
1781 * @access public
1782 * @return string
1783 */
1784 public function wrapText($message, $length, $qp_mode = false)
1785 {
ec9e2d04
CB
1786 if ($qp_mode) {
1787 $soft_break = sprintf(' =%s', $this->LE);
1788 } else {
1789 $soft_break = $this->LE;
1790 }
29bf99fd
PS
1791 // If utf-8 encoding is used, we will need to make sure we don't
1792 // split multibyte characters when we wrap
ccff58da 1793 $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
29bf99fd
PS
1794 $lelen = strlen($this->LE);
1795 $crlflen = strlen(self::CRLF);
1796
1797 $message = $this->fixEOL($message);
ec9e2d04 1798 //Remove a trailing line break
29bf99fd
PS
1799 if (substr($message, -$lelen) == $this->LE) {
1800 $message = substr($message, 0, -$lelen);
1801 }
1802
ec9e2d04
CB
1803 //Split message into lines
1804 $lines = explode($this->LE, $message);
1805 //Message will be rebuilt in here
29bf99fd 1806 $message = '';
ec9e2d04
CB
1807 foreach ($lines as $line) {
1808 $words = explode(' ', $line);
ed546836 1809 $buf = '';
ec9e2d04
CB
1810 $firstword = true;
1811 foreach ($words as $word) {
29bf99fd
PS
1812 if ($qp_mode and (strlen($word) > $length)) {
1813 $space_left = $length - strlen($buf) - $crlflen;
ec9e2d04 1814 if (!$firstword) {
29bf99fd
PS
1815 if ($space_left > 20) {
1816 $len = $space_left;
1817 if ($is_utf8) {
1818 $len = $this->utf8CharBoundary($word, $len);
ccff58da 1819 } elseif (substr($word, $len - 1, 1) == '=') {
29bf99fd 1820 $len--;
ccff58da 1821 } elseif (substr($word, $len - 2, 1) == '=') {
29bf99fd
PS
1822 $len -= 2;
1823 }
1824 $part = substr($word, 0, $len);
1825 $word = substr($word, $len);
1826 $buf .= ' ' . $part;
ccff58da 1827 $message .= $buf . sprintf('=%s', self::CRLF);
29bf99fd
PS
1828 } else {
1829 $message .= $buf . $soft_break;
1830 }
1831 $buf = '';
1832 }
1833 while (strlen($word) > 0) {
1834 if ($length <= 0) {
1835 break;
1836 }
1837 $len = $length;
1838 if ($is_utf8) {
1839 $len = $this->utf8CharBoundary($word, $len);
ccff58da 1840 } elseif (substr($word, $len - 1, 1) == '=') {
29bf99fd 1841 $len--;
ccff58da 1842 } elseif (substr($word, $len - 2, 1) == '=') {
29bf99fd
PS
1843 $len -= 2;
1844 }
1845 $part = substr($word, 0, $len);
1846 $word = substr($word, $len);
1847
1848 if (strlen($word) > 0) {
ccff58da 1849 $message .= $part . sprintf('=%s', self::CRLF);
29bf99fd
PS
1850 } else {
1851 $buf = $part;
1852 }
1853 }
1854 } else {
1855 $buf_o = $buf;
ec9e2d04
CB
1856 if (!$firstword) {
1857 $buf .= ' ';
1858 }
1859 $buf .= $word;
29bf99fd
PS
1860
1861 if (strlen($buf) > $length and $buf_o != '') {
1862 $message .= $buf_o . $soft_break;
1863 $buf = $word;
1864 }
1865 }
ec9e2d04 1866 $firstword = false;
346d4eab 1867 }
29bf99fd
PS
1868 $message .= $buf . self::CRLF;
1869 }
ed546836 1870
29bf99fd
PS
1871 return $message;
1872 }
1873
1874 /**
1875 * Find the last character boundary prior to $maxLength in a utf-8
ec9e2d04 1876 * quoted-printable encoded string.
29bf99fd
PS
1877 * Original written by Colin Brown.
1878 * @access public
1879 * @param string $encodedText utf-8 QP text
ec9e2d04 1880 * @param integer $maxLength Find the last character boundary prior to this length
ccff58da 1881 * @return integer
29bf99fd
PS
1882 */
1883 public function utf8CharBoundary($encodedText, $maxLength)
1884 {
1885 $foundSplitPos = false;
1886 $lookBack = 3;
1887 while (!$foundSplitPos) {
1888 $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
ccff58da 1889 $encodedCharPos = strpos($lastChunk, '=');
ec9e2d04 1890 if (false !== $encodedCharPos) {
29bf99fd
PS
1891 // Found start of encoded character byte within $lookBack block.
1892 // Check the encoded byte value (the 2 chars after the '=')
1893 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1894 $dec = hexdec($hex);
ec9e2d04
CB
1895 if ($dec < 128) {
1896 // Single byte character.
29bf99fd
PS
1897 // If the encoded char was found at pos 0, it will fit
1898 // otherwise reduce maxLength to start of the encoded char
ec9e2d04
CB
1899 if ($encodedCharPos > 0) {
1900 $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1901 }
29bf99fd 1902 $foundSplitPos = true;
ec9e2d04
CB
1903 } elseif ($dec >= 192) {
1904 // First byte of a multi byte character
29bf99fd
PS
1905 // Reduce maxLength to split at start of character
1906 $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1907 $foundSplitPos = true;
ec9e2d04
CB
1908 } elseif ($dec < 192) {
1909 // Middle byte of a multi byte character, look further back
29bf99fd
PS
1910 $lookBack += 3;
1911 }
ed546836 1912 } else {
29bf99fd
PS
1913 // No encoded character found
1914 $foundSplitPos = true;
706be214 1915 }
29bf99fd
PS
1916 }
1917 return $maxLength;
1918 }
1919
29bf99fd 1920 /**
ec9e2d04
CB
1921 * Apply word wrapping to the message body.
1922 * Wraps the message body to the number of chars set in the WordWrap property.
1923 * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1924 * This is called automatically by createBody(), so you don't need to call it yourself.
29bf99fd
PS
1925 * @access public
1926 * @return void
1927 */
1928 public function setWordWrap()
1929 {
1930 if ($this->WordWrap < 1) {
1931 return;
1932 }
1933
1934 switch ($this->message_type) {
1935 case 'alt':
1936 case 'alt_inline':
1937 case 'alt_attach':
1938 case 'alt_inline_attach':
1939 $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
1940 break;
1941 default:
1942 $this->Body = $this->wrapText($this->Body, $this->WordWrap);
1943 break;
1944 }
1945 }
1946
1947 /**
1948 * Assemble message headers.
1949 * @access public
1950 * @return string The assembled headers
1951 */
1952 public function createHeader()
1953 {
1954 $result = '';
1955
29bf99fd 1956 if ($this->MessageDate == '') {
ccff58da 1957 $this->MessageDate = self::rfcDate();
c1ccd3dd 1958 }
ccff58da 1959 $result .= $this->headerLine('Date', $this->MessageDate);
29bf99fd 1960
29bf99fd 1961 // To be created automatically by mail()
ec9e2d04 1962 if ($this->SingleTo) {
ccff58da
MG
1963 if ($this->Mailer != 'mail') {
1964 foreach ($this->to as $toaddr) {
1965 $this->SingleToArray[] = $this->addrFormat($toaddr);
29bf99fd 1966 }
ccff58da
MG
1967 }
1968 } else {
1969 if (count($this->to) > 0) {
1970 if ($this->Mailer != 'mail') {
29bf99fd 1971 $result .= $this->addrAppend('To', $this->to);
29bf99fd 1972 }
ccff58da
MG
1973 } elseif (count($this->cc) == 0) {
1974 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
29bf99fd
PS
1975 }
1976 }
0747daba 1977
29bf99fd 1978 $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
0747daba 1979
29bf99fd
PS
1980 // sendmail and mail() extract Cc from the header before sending
1981 if (count($this->cc) > 0) {
1982 $result .= $this->addrAppend('Cc', $this->cc);
0747daba 1983 }
c1ccd3dd 1984
29bf99fd 1985 // sendmail and mail() extract Bcc from the header before sending
ccff58da
MG
1986 if ((
1987 $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
1988 )
1989 and count($this->bcc) > 0
1990 ) {
29bf99fd
PS
1991 $result .= $this->addrAppend('Bcc', $this->bcc);
1992 }
c1ccd3dd 1993
29bf99fd
PS
1994 if (count($this->ReplyTo) > 0) {
1995 $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
1996 }
1997
1998 // mail() sets the subject itself
1999 if ($this->Mailer != 'mail') {
2000 $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2001 }
2002
48dc4059 2003 if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
29bf99fd 2004 $this->lastMessageID = $this->MessageID;
0747daba 2005 } else {
30f4e2d3 2006 $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
ec9e2d04
CB
2007 }
2008 $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2009 if (!is_null($this->Priority)) {
2010 $result .= $this->headerLine('X-Priority', $this->Priority);
29bf99fd 2011 }
29bf99fd
PS
2012 if ($this->XMailer == '') {
2013 $result .= $this->headerLine(
2014 'X-Mailer',
30f4e2d3 2015 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
29bf99fd 2016 );
0747daba 2017 } else {
29bf99fd
PS
2018 $myXmailer = trim($this->XMailer);
2019 if ($myXmailer) {
2020 $result .= $this->headerLine('X-Mailer', $myXmailer);
2021 }
2022 }
2023
2024 if ($this->ConfirmReadingTo != '') {
30f4e2d3 2025 $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
29bf99fd
PS
2026 }
2027
2028 // Add custom headers
ec9e2d04 2029 foreach ($this->CustomHeader as $header) {
29bf99fd 2030 $result .= $this->headerLine(
ec9e2d04
CB
2031 trim($header[0]),
2032 $this->encodeHeader(trim($header[1]))
29bf99fd
PS
2033 );
2034 }
2035 if (!$this->sign_key_file) {
2036 $result .= $this->headerLine('MIME-Version', '1.0');
2037 $result .= $this->getMailMIME();
2038 }
2039
2040 return $result;
2041 }
2042
2043 /**
2044 * Get the message MIME type headers.
2045 * @access public
2046 * @return string
2047 */
2048 public function getMailMIME()
2049 {
2050 $result = '';
ccff58da 2051 $ismultipart = true;
29bf99fd
PS
2052 switch ($this->message_type) {
2053 case 'inline':
2054 $result .= $this->headerLine('Content-Type', 'multipart/related;');
2055 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2056 break;
2057 case 'attach':
2058 case 'inline_attach':
2059 case 'alt_attach':
2060 case 'alt_inline_attach':
2061 $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2062 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2063 break;
2064 case 'alt':
2065 case 'alt_inline':
2066 $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2067 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2068 break;
2069 default:
2070 // Catches case 'plain': and case '':
2071 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
ccff58da 2072 $ismultipart = false;
29bf99fd
PS
2073 break;
2074 }
ccff58da 2075 // RFC1341 part 5 says 7bit is assumed if not specified
29bf99fd 2076 if ($this->Encoding != '7bit') {
ccff58da
MG
2077 // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2078 if ($ismultipart) {
2079 if ($this->Encoding == '8bit') {
2080 $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2081 }
2082 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2083 } else {
2084 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2085 }
29bf99fd
PS
2086 }
2087
2088 if ($this->Mailer != 'mail') {
2089 $result .= $this->LE;
2090 }
2091
2092 return $result;
2093 }
2094
2095 /**
2096 * Returns the whole MIME message.
2097 * Includes complete headers and body.
ccff58da
MG
2098 * Only valid post preSend().
2099 * @see PHPMailer::preSend()
29bf99fd
PS
2100 * @access public
2101 * @return string
2102 */
2103 public function getSentMIMEMessage()
2104 {
48dc4059 2105 return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
29bf99fd
PS
2106 }
2107
29bf99fd
PS
2108 /**
2109 * Assemble the message body.
2110 * Returns an empty string on failure.
2111 * @access public
2112 * @throws phpmailerException
2113 * @return string The assembled message body
2114 */
2115 public function createBody()
2116 {
2117 $body = '';
ec9e2d04
CB
2118 //Create unique IDs and preset boundaries
2119 $this->uniqueid = md5(uniqid(time()));
2120 $this->boundary[1] = 'b1_' . $this->uniqueid;
2121 $this->boundary[2] = 'b2_' . $this->uniqueid;
2122 $this->boundary[3] = 'b3_' . $this->uniqueid;
29bf99fd
PS
2123
2124 if ($this->sign_key_file) {
2125 $body .= $this->getMailMIME() . $this->LE;
2126 }
2127
2128 $this->setWordWrap();
2129
ccff58da
MG
2130 $bodyEncoding = $this->Encoding;
2131 $bodyCharSet = $this->CharSet;
ec9e2d04 2132 //Can we do a 7-bit downgrade?
ccff58da
MG
2133 if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2134 $bodyEncoding = '7bit';
48dc4059 2135 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
ccff58da
MG
2136 $bodyCharSet = 'us-ascii';
2137 }
ec9e2d04 2138 //If lines are too long, and we're not already using an encoding that will shorten them,
48dc4059 2139 //change to quoted-printable transfer encoding for the body part only
ec9e2d04 2140 if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
ec9e2d04
CB
2141 $bodyEncoding = 'quoted-printable';
2142 }
2143
ccff58da
MG
2144 $altBodyEncoding = $this->Encoding;
2145 $altBodyCharSet = $this->CharSet;
ec9e2d04 2146 //Can we do a 7-bit downgrade?
ccff58da
MG
2147 if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2148 $altBodyEncoding = '7bit';
48dc4059 2149 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
ccff58da
MG
2150 $altBodyCharSet = 'us-ascii';
2151 }
48dc4059
SL
2152 //If lines are too long, and we're not already using an encoding that will shorten them,
2153 //change to quoted-printable transfer encoding for the alt body part only
2154 if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
ec9e2d04
CB
2155 $altBodyEncoding = 'quoted-printable';
2156 }
2157 //Use this as a preamble in all multipart message types
2158 $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
29bf99fd
PS
2159 switch ($this->message_type) {
2160 case 'inline':
ec9e2d04 2161 $body .= $mimepre;
ccff58da
MG
2162 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2163 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2164 $body .= $this->LE . $this->LE;
2165 $body .= $this->attachAll('inline', $this->boundary[1]);
2166 break;
2167 case 'attach':
ec9e2d04 2168 $body .= $mimepre;
ccff58da
MG
2169 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2170 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2171 $body .= $this->LE . $this->LE;
2172 $body .= $this->attachAll('attachment', $this->boundary[1]);
2173 break;
2174 case 'inline_attach':
ec9e2d04 2175 $body .= $mimepre;
29bf99fd
PS
2176 $body .= $this->textLine('--' . $this->boundary[1]);
2177 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2178 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2179 $body .= $this->LE;
ccff58da
MG
2180 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2181 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2182 $body .= $this->LE . $this->LE;
2183 $body .= $this->attachAll('inline', $this->boundary[2]);
2184 $body .= $this->LE;
2185 $body .= $this->attachAll('attachment', $this->boundary[1]);
2186 break;
2187 case 'alt':
ec9e2d04 2188 $body .= $mimepre;
ccff58da
MG
2189 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2190 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
29bf99fd 2191 $body .= $this->LE . $this->LE;
ccff58da
MG
2192 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2193 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2194 $body .= $this->LE . $this->LE;
2195 if (!empty($this->Ical)) {
2196 $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2197 $body .= $this->encodeString($this->Ical, $this->Encoding);
2198 $body .= $this->LE . $this->LE;
2199 }
2200 $body .= $this->endBoundary($this->boundary[1]);
2201 break;
2202 case 'alt_inline':
ec9e2d04 2203 $body .= $mimepre;
ccff58da
MG
2204 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2205 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
29bf99fd
PS
2206 $body .= $this->LE . $this->LE;
2207 $body .= $this->textLine('--' . $this->boundary[1]);
2208 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2209 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2210 $body .= $this->LE;
ccff58da
MG
2211 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2212 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2213 $body .= $this->LE . $this->LE;
2214 $body .= $this->attachAll('inline', $this->boundary[2]);
2215 $body .= $this->LE;
2216 $body .= $this->endBoundary($this->boundary[1]);
2217 break;
2218 case 'alt_attach':
ec9e2d04 2219 $body .= $mimepre;
29bf99fd
PS
2220 $body .= $this->textLine('--' . $this->boundary[1]);
2221 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2222 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2223 $body .= $this->LE;
ccff58da
MG
2224 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2225 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
29bf99fd 2226 $body .= $this->LE . $this->LE;
ccff58da
MG
2227 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2228 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2229 $body .= $this->LE . $this->LE;
2230 $body .= $this->endBoundary($this->boundary[2]);
2231 $body .= $this->LE;
2232 $body .= $this->attachAll('attachment', $this->boundary[1]);
2233 break;
2234 case 'alt_inline_attach':
ec9e2d04 2235 $body .= $mimepre;
29bf99fd
PS
2236 $body .= $this->textLine('--' . $this->boundary[1]);
2237 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2238 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2239 $body .= $this->LE;
ccff58da
MG
2240 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2241 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
29bf99fd
PS
2242 $body .= $this->LE . $this->LE;
2243 $body .= $this->textLine('--' . $this->boundary[2]);
2244 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2245 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2246 $body .= $this->LE;
ccff58da
MG
2247 $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2248 $body .= $this->encodeString($this->Body, $bodyEncoding);
29bf99fd
PS
2249 $body .= $this->LE . $this->LE;
2250 $body .= $this->attachAll('inline', $this->boundary[3]);
2251 $body .= $this->LE;
2252 $body .= $this->endBoundary($this->boundary[2]);
2253 $body .= $this->LE;
2254 $body .= $this->attachAll('attachment', $this->boundary[1]);
2255 break;
2256 default:
48dc4059
SL
2257 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
2258 //Reset the `Encoding` property in case we changed it for line length reasons
2259 $this->Encoding = $bodyEncoding;
2260 $body .= $this->encodeString($this->Body, $this->Encoding);
29bf99fd
PS
2261 break;
2262 }
2263
2264 if ($this->isError()) {
2265 $body = '';
2266 } elseif ($this->sign_key_file) {
2267 try {
2268 if (!defined('PKCS7_TEXT')) {
ec9e2d04 2269 throw new phpmailerException($this->lang('extension_missing') . 'openssl');
29bf99fd 2270 }
ccff58da 2271 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
29bf99fd 2272 $file = tempnam(sys_get_temp_dir(), 'mail');
ec9e2d04
CB
2273 if (false === file_put_contents($file, $body)) {
2274 throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2275 }
29bf99fd 2276 $signed = tempnam(sys_get_temp_dir(), 'signed');
ec9e2d04
CB
2277 //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2278 if (empty($this->sign_extracerts_file)) {
2279 $sign = @openssl_pkcs7_sign(
2280 $file,
2281 $signed,
2282 'file://' . realpath($this->sign_cert_file),
2283 array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2284 null
2285 );
2286 } else {
2287 $sign = @openssl_pkcs7_sign(
2288 $file,
2289 $signed,
2290 'file://' . realpath($this->sign_cert_file),
2291 array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2292 null,
2293 PKCS7_DETACHED,
2294 $this->sign_extracerts_file
2295 );
2296 }
2297 if ($sign) {
29bf99fd
PS
2298 @unlink($file);
2299 $body = file_get_contents($signed);
2300 @unlink($signed);
ec9e2d04
CB
2301 //The message returned by openssl contains both headers and body, so need to split them up
2302 $parts = explode("\n\n", $body, 2);
2303 $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2304 $body = $parts[1];
29bf99fd
PS
2305 } else {
2306 @unlink($file);
2307 @unlink($signed);
2308 throw new phpmailerException($this->lang('signing') . openssl_error_string());
2309 }
ccff58da 2310 } catch (phpmailerException $exc) {
29bf99fd
PS
2311 $body = '';
2312 if ($this->exceptions) {
ccff58da 2313 throw $exc;
29bf99fd
PS
2314 }
2315 }
2316 }
2317 return $body;
2318 }
2319
2320 /**
2321 * Return the start of a message boundary.
2322 * @access protected
2323 * @param string $boundary
2324 * @param string $charSet
2325 * @param string $contentType
2326 * @param string $encoding
2327 * @return string
2328 */
2329 protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2330 {
2331 $result = '';
2332 if ($charSet == '') {
2333 $charSet = $this->CharSet;
2334 }
2335 if ($contentType == '') {
2336 $contentType = $this->ContentType;
2337 }
2338 if ($encoding == '') {
2339 $encoding = $this->Encoding;
2340 }
2341 $result .= $this->textLine('--' . $boundary);
ccff58da 2342 $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
29bf99fd 2343 $result .= $this->LE;
ccff58da
MG
2344 // RFC1341 part 5 says 7bit is assumed if not specified
2345 if ($encoding != '7bit') {
2346 $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2347 }
29bf99fd
PS
2348 $result .= $this->LE;
2349
2350 return $result;
2351 }
2352
2353 /**
2354 * Return the end of a message boundary.
2355 * @access protected
2356 * @param string $boundary
2357 * @return string
2358 */
2359 protected function endBoundary($boundary)
2360 {
2361 return $this->LE . '--' . $boundary . '--' . $this->LE;
2362 }
2363
2364 /**
2365 * Set the message type.
48dc4059 2366 * PHPMailer only supports some preset message types, not arbitrary MIME structures.
29bf99fd
PS
2367 * @access protected
2368 * @return void
2369 */
2370 protected function setMessageType()
2371 {
ccff58da 2372 $type = array();
29bf99fd 2373 if ($this->alternativeExists()) {
ccff58da 2374 $type[] = 'alt';
29bf99fd
PS
2375 }
2376 if ($this->inlineImageExists()) {
ccff58da 2377 $type[] = 'inline';
29bf99fd
PS
2378 }
2379 if ($this->attachmentExists()) {
ccff58da 2380 $type[] = 'attach';
29bf99fd 2381 }
ccff58da
MG
2382 $this->message_type = implode('_', $type);
2383 if ($this->message_type == '') {
48dc4059 2384 //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
ccff58da 2385 $this->message_type = 'plain';
29bf99fd
PS
2386 }
2387 }
2388
2389 /**
2390 * Format a header line.
2391 * @access public
2392 * @param string $name
2393 * @param string $value
2394 * @return string
2395 */
2396 public function headerLine($name, $value)
2397 {
2398 return $name . ': ' . $value . $this->LE;
2399 }
2400
2401 /**
2402 * Return a formatted mail line.
2403 * @access public
2404 * @param string $value
2405 * @return string
2406 */
2407 public function textLine($value)
2408 {
2409 return $value . $this->LE;
2410 }
2411
2412 /**
2413 * Add an attachment from a path on the filesystem.
2414 * Returns false if the file could not be found or read.
2415 * @param string $path Path to the attachment.
2416 * @param string $name Overrides the attachment name.
2417 * @param string $encoding File encoding (see $Encoding).
2418 * @param string $type File extension (MIME) type.
2419 * @param string $disposition Disposition to use
2420 * @throws phpmailerException
ccff58da 2421 * @return boolean
29bf99fd
PS
2422 */
2423 public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2424 {
2425 try {
2426 if (!@is_file($path)) {
2427 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2428 }
2429
ccff58da 2430 // If a MIME type is not specified, try to work it out from the file name
29bf99fd
PS
2431 if ($type == '') {
2432 $type = self::filenameToType($path);
2433 }
2434
2435 $filename = basename($path);
2436 if ($name == '') {
2437 $name = $filename;
2438 }
2439
2440 $this->attachment[] = array(
2441 0 => $path,
2442 1 => $filename,
2443 2 => $name,
2444 3 => $encoding,
2445 4 => $type,
2446 5 => false, // isStringAttachment
2447 6 => $disposition,
2448 7 => 0
2449 );
2450
ccff58da
MG
2451 } catch (phpmailerException $exc) {
2452 $this->setError($exc->getMessage());
2453 $this->edebug($exc->getMessage());
29bf99fd 2454 if ($this->exceptions) {
ccff58da 2455 throw $exc;
29bf99fd 2456 }
29bf99fd
PS
2457 return false;
2458 }
2459 return true;
2460 }
2461
2462 /**
2463 * Return the array of attachments.
2464 * @return array
2465 */
2466 public function getAttachments()
2467 {
2468 return $this->attachment;
2469 }
2470
2471 /**
2472 * Attach all file, string, and binary attachments to the message.
2473 * Returns an empty string on failure.
2474 * @access protected
2475 * @param string $disposition_type
2476 * @param string $boundary
2477 * @return string
2478 */
2479 protected function attachAll($disposition_type, $boundary)
2480 {
2481 // Return text of body
2482 $mime = array();
2483 $cidUniq = array();
2484 $incl = array();
2485
2486 // Add all attachments
2487 foreach ($this->attachment as $attachment) {
2488 // Check if it is a valid disposition_filter
2489 if ($attachment[6] == $disposition_type) {
2490 // Check for string attachment
2491 $string = '';
2492 $path = '';
2493 $bString = $attachment[5];
2494 if ($bString) {
2495 $string = $attachment[0];
2496 } else {
2497 $path = $attachment[0];
2498 }
2499
2500 $inclhash = md5(serialize($attachment));
2501 if (in_array($inclhash, $incl)) {
2502 continue;
2503 }
2504 $incl[] = $inclhash;
2505 $name = $attachment[2];
2506 $encoding = $attachment[3];
2507 $type = $attachment[4];
2508 $disposition = $attachment[6];
2509 $cid = $attachment[7];
30f4e2d3 2510 if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
29bf99fd
PS
2511 continue;
2512 }
2513 $cidUniq[$cid] = true;
2514
ccff58da 2515 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
ec9e2d04
CB
2516 //Only include a filename property if we have one
2517 if (!empty($name)) {
2518 $mime[] = sprintf(
2519 'Content-Type: %s; name="%s"%s',
2520 $type,
2521 $this->encodeHeader($this->secureHeader($name)),
2522 $this->LE
2523 );
2524 } else {
2525 $mime[] = sprintf(
2526 'Content-Type: %s%s',
2527 $type,
2528 $this->LE
2529 );
2530 }
ccff58da
MG
2531 // RFC1341 part 5 says 7bit is assumed if not specified
2532 if ($encoding != '7bit') {
2533 $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2534 }
29bf99fd
PS
2535
2536 if ($disposition == 'inline') {
ccff58da 2537 $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
29bf99fd
PS
2538 }
2539
2540 // If a filename contains any of these chars, it should be quoted,
2541 // but not otherwise: RFC2183 & RFC2045 5.1
2542 // Fixes a warning in IETF's msglint MIME checker
2543 // Allow for bypassing the Content-Disposition header totally
2544 if (!(empty($disposition))) {
ccff58da
MG
2545 $encoded_name = $this->encodeHeader($this->secureHeader($name));
2546 if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
29bf99fd 2547 $mime[] = sprintf(
ccff58da 2548 'Content-Disposition: %s; filename="%s"%s',
29bf99fd 2549 $disposition,
ccff58da 2550 $encoded_name,
29bf99fd
PS
2551 $this->LE . $this->LE
2552 );
2553 } else {
ec9e2d04
CB
2554 if (!empty($encoded_name)) {
2555 $mime[] = sprintf(
2556 'Content-Disposition: %s; filename=%s%s',
2557 $disposition,
2558 $encoded_name,
2559 $this->LE . $this->LE
2560 );
2561 } else {
2562 $mime[] = sprintf(
2563 'Content-Disposition: %s%s',
2564 $disposition,
2565 $this->LE . $this->LE
2566 );
2567 }
29bf99fd
PS
2568 }
2569 } else {
2570 $mime[] = $this->LE;
2571 }
2572
2573 // Encode as string attachment
2574 if ($bString) {
2575 $mime[] = $this->encodeString($string, $encoding);
2576 if ($this->isError()) {
2577 return '';
2578 }
2579 $mime[] = $this->LE . $this->LE;
2580 } else {
2581 $mime[] = $this->encodeFile($path, $encoding);
2582 if ($this->isError()) {
2583 return '';
2584 }
2585 $mime[] = $this->LE . $this->LE;
2586 }
2587 }
2588 }
2589
ccff58da 2590 $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
29bf99fd 2591
ccff58da 2592 return implode('', $mime);
29bf99fd
PS
2593 }
2594
2595 /**
2596 * Encode a file attachment in requested format.
2597 * Returns an empty string on failure.
2598 * @param string $path The full path to the file
2599 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2600 * @throws phpmailerException
29bf99fd
PS
2601 * @access protected
2602 * @return string
2603 */
2604 protected function encodeFile($path, $encoding = 'base64')
2605 {
2606 try {
2607 if (!is_readable($path)) {
2608 throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2609 }
2610 $magic_quotes = get_magic_quotes_runtime();
2611 if ($magic_quotes) {
2612 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
ccff58da 2613 set_magic_quotes_runtime(false);
29bf99fd 2614 } else {
ccff58da
MG
2615 //Doesn't exist in PHP 5.4, but we don't need to check because
2616 //get_magic_quotes_runtime always returns false in 5.4+
2617 //so it will never get here
ec9e2d04 2618 ini_set('magic_quotes_runtime', false);
29bf99fd
PS
2619 }
2620 }
2621 $file_buffer = file_get_contents($path);
2622 $file_buffer = $this->encodeString($file_buffer, $encoding);
2623 if ($magic_quotes) {
2624 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2625 set_magic_quotes_runtime($magic_quotes);
2626 } else {
ec9e2d04 2627 ini_set('magic_quotes_runtime', $magic_quotes);
29bf99fd
PS
2628 }
2629 }
2630 return $file_buffer;
ccff58da
MG
2631 } catch (Exception $exc) {
2632 $this->setError($exc->getMessage());
29bf99fd
PS
2633 return '';
2634 }
2635 }
2636
2637 /**
2638 * Encode a string in requested format.
2639 * Returns an empty string on failure.
2640 * @param string $str The text to encode
2641 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2642 * @access public
2643 * @return string
2644 */
2645 public function encodeString($str, $encoding = 'base64')
2646 {
2647 $encoded = '';
2648 switch (strtolower($encoding)) {
2649 case 'base64':
2650 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2651 break;
2652 case '7bit':
2653 case '8bit':
2654 $encoded = $this->fixEOL($str);
ccff58da 2655 // Make sure it ends with a line break
29bf99fd
PS
2656 if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2657 $encoded .= $this->LE;
2658 }
2659 break;
2660 case 'binary':
2661 $encoded = $str;
2662 break;
2663 case 'quoted-printable':
2664 $encoded = $this->encodeQP($str);
2665 break;
2666 default:
2667 $this->setError($this->lang('encoding') . $encoding);
2668 break;
2669 }
2670 return $encoded;
2671 }
2672
2673 /**
2674 * Encode a header string optimally.
2675 * Picks shortest of Q, B, quoted-printable or none.
2676 * @access public
2677 * @param string $str
2678 * @param string $position
2679 * @return string
2680 */
2681 public function encodeHeader($str, $position = 'text')
2682 {
ccff58da 2683 $matchcount = 0;
29bf99fd
PS
2684 switch (strtolower($position)) {
2685 case 'phrase':
2686 if (!preg_match('/[\200-\377]/', $str)) {
ccff58da 2687 // Can't use addslashes as we don't know the value of magic_quotes_sybase
29bf99fd
PS
2688 $encoded = addcslashes($str, "\0..\37\177\\\"");
2689 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2690 return ($encoded);
2691 } else {
2692 return ("\"$encoded\"");
2693 }
2694 }
ccff58da 2695 $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
29bf99fd
PS
2696 break;
2697 /** @noinspection PhpMissingBreakStatementInspection */
2698 case 'comment':
ccff58da 2699 $matchcount = preg_match_all('/[()"]/', $str, $matches);
29bf99fd
PS
2700 // Intentional fall-through
2701 case 'text':
2702 default:
ccff58da 2703 $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
29bf99fd
PS
2704 break;
2705 }
2706
ec9e2d04
CB
2707 //There are no chars that need encoding
2708 if ($matchcount == 0) {
29bf99fd
PS
2709 return ($str);
2710 }
2711
2712 $maxlen = 75 - 7 - strlen($this->CharSet);
2713 // Try to select the encoding which should produce the shortest output
ccff58da
MG
2714 if ($matchcount > strlen($str) / 3) {
2715 // More than a third of the content will need encoding, so B encoding will be most efficient
29bf99fd
PS
2716 $encoding = 'B';
2717 if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2718 // Use a custom function which correctly encodes and wraps long
2719 // multibyte strings without breaking lines within a character
2720 $encoded = $this->base64EncodeWrapMB($str, "\n");
2721 } else {
2722 $encoded = base64_encode($str);
2723 $maxlen -= $maxlen % 4;
2724 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2725 }
0747daba 2726 } else {
29bf99fd
PS
2727 $encoding = 'Q';
2728 $encoded = $this->encodeQ($str, $position);
2729 $encoded = $this->wrapText($encoded, $maxlen, true);
2730 $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2731 }
2732
ccff58da 2733 $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
29bf99fd
PS
2734 $encoded = trim(str_replace("\n", $this->LE, $encoded));
2735
2736 return $encoded;
2737 }
2738
2739 /**
2740 * Check if a string contains multi-byte characters.
2741 * @access public
2742 * @param string $str multi-byte text to wrap encode
ccff58da 2743 * @return boolean
29bf99fd
PS
2744 */
2745 public function hasMultiBytes($str)
2746 {
2747 if (function_exists('mb_strlen')) {
2748 return (strlen($str) > mb_strlen($str, $this->CharSet));
2749 } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2750 return false;
2751 }
2752 }
2753
ccff58da
MG
2754 /**
2755 * Does a string contain any 8-bit chars (in any charset)?
2756 * @param string $text
2757 * @return boolean
2758 */
2759 public function has8bitChars($text)
2760 {
2761 return (boolean)preg_match('/[\x80-\xFF]/', $text);
2762 }
2763
29bf99fd
PS
2764 /**
2765 * Encode and wrap long multibyte strings for mail headers
2766 * without breaking lines within a character.
ccff58da
MG
2767 * Adapted from a function by paravoid
2768 * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
29bf99fd
PS
2769 * @access public
2770 * @param string $str multi-byte text to wrap encode
ccff58da 2771 * @param string $linebreak string to use as linefeed/end-of-line
29bf99fd
PS
2772 * @return string
2773 */
ccff58da 2774 public function base64EncodeWrapMB($str, $linebreak = null)
29bf99fd 2775 {
ccff58da
MG
2776 $start = '=?' . $this->CharSet . '?B?';
2777 $end = '?=';
2778 $encoded = '';
2779 if ($linebreak === null) {
2780 $linebreak = $this->LE;
29bf99fd
PS
2781 }
2782
2783 $mb_length = mb_strlen($str, $this->CharSet);
2784 // Each line must have length <= 75, including $start and $end
2785 $length = 75 - strlen($start) - strlen($end);
2786 // Average multi-byte ratio
2787 $ratio = $mb_length / strlen($str);
2788 // Base64 has a 4:3 ratio
2789 $avgLength = floor($length * $ratio * .75);
2790
2791 for ($i = 0; $i < $mb_length; $i += $offset) {
2792 $lookBack = 0;
2793 do {
2794 $offset = $avgLength - $lookBack;
2795 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2796 $chunk = base64_encode($chunk);
2797 $lookBack++;
2798 } while (strlen($chunk) > $length);
ccff58da 2799 $encoded .= $chunk . $linebreak;
29bf99fd
PS
2800 }
2801
2802 // Chomp the last linefeed
ccff58da 2803 $encoded = substr($encoded, 0, -strlen($linebreak));
29bf99fd
PS
2804 return $encoded;
2805 }
2806
2807 /**
2808 * Encode a string in quoted-printable format.
2809 * According to RFC2045 section 6.7.
2810 * @access public
2811 * @param string $string The text to encode
2812 * @param integer $line_max Number of chars allowed on a line before wrapping
2813 * @return string
ccff58da 2814 * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
29bf99fd
PS
2815 */
2816 public function encodeQP($string, $line_max = 76)
2817 {
ec9e2d04
CB
2818 // Use native function if it's available (>= PHP5.3)
2819 if (function_exists('quoted_printable_encode')) {
2820 return quoted_printable_encode($string);
29bf99fd 2821 }
ccff58da 2822 // Fall back to a pure PHP implementation
29bf99fd
PS
2823 $string = str_replace(
2824 array('%20', '%0D%0A.', '%0D%0A', '%'),
2825 array(' ', "\r\n=2E", "\r\n", '='),
2826 rawurlencode($string)
2827 );
ec9e2d04 2828 return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
29bf99fd
PS
2829 }
2830
2831 /**
2832 * Backward compatibility wrapper for an old QP encoding function that was removed.
2833 * @see PHPMailer::encodeQP()
2834 * @access public
2835 * @param string $string
2836 * @param integer $line_max
ccff58da 2837 * @param boolean $space_conv
29bf99fd
PS
2838 * @return string
2839 * @deprecated Use encodeQP instead.
2840 */
2841 public function encodeQPphp(
2842 $string,
2843 $line_max = 76,
2844 /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
2845 ) {
2846 return $this->encodeQP($string, $line_max);
2847 }
2848
2849 /**
2850 * Encode a string using Q encoding.
2851 * @link http://tools.ietf.org/html/rfc2047
2852 * @param string $str the text to encode
2853 * @param string $position Where the text is going to be used, see the RFC for what that means
2854 * @access public
2855 * @return string
2856 */
2857 public function encodeQ($str, $position = 'text')
2858 {
ccff58da 2859 // There should not be any EOL in the string
29bf99fd
PS
2860 $pattern = '';
2861 $encoded = str_replace(array("\r", "\n"), '', $str);
2862 switch (strtolower($position)) {
2863 case 'phrase':
ccff58da 2864 // RFC 2047 section 5.3
29bf99fd
PS
2865 $pattern = '^A-Za-z0-9!*+\/ -';
2866 break;
2867 /** @noinspection PhpMissingBreakStatementInspection */
2868 case 'comment':
ccff58da 2869 // RFC 2047 section 5.2
29bf99fd 2870 $pattern = '\(\)"';
ccff58da
MG
2871 // intentional fall-through
2872 // for this reason we build the $pattern without including delimiters and []
29bf99fd
PS
2873 case 'text':
2874 default:
ccff58da
MG
2875 // RFC 2047 section 5.1
2876 // Replace every high ascii, control, =, ? and _ characters
29bf99fd
PS
2877 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2878 break;
2879 }
2880 $matches = array();
2881 if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
ccff58da
MG
2882 // If the string contains an '=', make sure it's the first thing we replace
2883 // so as to avoid double-encoding
2884 $eqkey = array_search('=', $matches[0]);
ec9e2d04 2885 if (false !== $eqkey) {
ccff58da 2886 unset($matches[0][$eqkey]);
29bf99fd
PS
2887 array_unshift($matches[0], '=');
2888 }
2889 foreach (array_unique($matches[0]) as $char) {
2890 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2891 }
2892 }
ccff58da 2893 // Replace every spaces to _ (more readable than =20)
29bf99fd
PS
2894 return str_replace(' ', '_', $encoded);
2895 }
2896
29bf99fd
PS
2897 /**
2898 * Add a string or binary attachment (non-filesystem).
2899 * This method can be used to attach ascii or binary data,
2900 * such as a BLOB record from a database.
2901 * @param string $string String attachment data.
2902 * @param string $filename Name of the attachment.
2903 * @param string $encoding File encoding (see $Encoding).
2904 * @param string $type File extension (MIME) type.
2905 * @param string $disposition Disposition to use
2906 * @return void
2907 */
2908 public function addStringAttachment(
2909 $string,
2910 $filename,
2911 $encoding = 'base64',
2912 $type = '',
2913 $disposition = 'attachment'
2914 ) {
ccff58da 2915 // If a MIME type is not specified, try to work it out from the file name
29bf99fd
PS
2916 if ($type == '') {
2917 $type = self::filenameToType($filename);
2918 }
2919 // Append to $attachment array
2920 $this->attachment[] = array(
2921 0 => $string,
2922 1 => $filename,
2923 2 => basename($filename),
2924 3 => $encoding,
2925 4 => $type,
2926 5 => true, // isStringAttachment
2927 6 => $disposition,
2928 7 => 0
2929 );
2930 }
2931
2932 /**
2933 * Add an embedded (inline) attachment from a file.
2934 * This can include images, sounds, and just about any other document type.
ec9e2d04 2935 * These differ from 'regular' attachments in that they are intended to be
29bf99fd
PS
2936 * displayed inline with the message, not just attached for download.
2937 * This is used in HTML messages that embed the images
2938 * the HTML refers to using the $cid value.
2939 * @param string $path Path to the attachment.
2940 * @param string $cid Content ID of the attachment; Use this to reference
2941 * the content when using an embedded image in HTML.
2942 * @param string $name Overrides the attachment name.
2943 * @param string $encoding File encoding (see $Encoding).
2944 * @param string $type File MIME type.
2945 * @param string $disposition Disposition to use
ccff58da 2946 * @return boolean True on successfully adding an attachment
29bf99fd
PS
2947 */
2948 public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
2949 {
2950 if (!@is_file($path)) {
2951 $this->setError($this->lang('file_access') . $path);
2952 return false;
2953 }
2954
ccff58da 2955 // If a MIME type is not specified, try to work it out from the file name
29bf99fd
PS
2956 if ($type == '') {
2957 $type = self::filenameToType($path);
2958 }
2959
2960 $filename = basename($path);
2961 if ($name == '') {
2962 $name = $filename;
2963 }
2964
2965 // Append to $attachment array
2966 $this->attachment[] = array(
2967 0 => $path,
2968 1 => $filename,
2969 2 => $name,
2970 3 => $encoding,
2971 4 => $type,
2972 5 => false, // isStringAttachment
2973 6 => $disposition,
2974 7 => $cid
2975 );
0b821adf 2976 return true;
2977 }
ed546836 2978
29bf99fd
PS
2979 /**
2980 * Add an embedded stringified attachment.
2981 * This can include images, sounds, and just about any other document type.
2982 * Be sure to set the $type to an image type for images:
2983 * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
2984 * @param string $string The attachment binary data.
2985 * @param string $cid Content ID of the attachment; Use this to reference
2986 * the content when using an embedded image in HTML.
2987 * @param string $name
2988 * @param string $encoding File encoding (see $Encoding).
2989 * @param string $type MIME type.
2990 * @param string $disposition Disposition to use
ccff58da 2991 * @return boolean True on successfully adding an attachment
29bf99fd
PS
2992 */
2993 public function addStringEmbeddedImage(
2994 $string,
2995 $cid,
2996 $name = '',
2997 $encoding = 'base64',
2998 $type = '',
2999 $disposition = 'inline'
3000 ) {
ccff58da 3001 // If a MIME type is not specified, try to work it out from the name
ec9e2d04 3002 if ($type == '' and !empty($name)) {
29bf99fd
PS
3003 $type = self::filenameToType($name);
3004 }
3005
3006 // Append to $attachment array
3007 $this->attachment[] = array(
3008 0 => $string,
3009 1 => $name,
3010 2 => $name,
3011 3 => $encoding,
3012 4 => $type,
3013 5 => true, // isStringAttachment
3014 6 => $disposition,
3015 7 => $cid
3016 );
0747daba 3017 return true;
29bf99fd
PS
3018 }
3019
3020 /**
3021 * Check if an inline attachment is present.
3022 * @access public
ccff58da 3023 * @return boolean
29bf99fd
PS
3024 */
3025 public function inlineImageExists()
3026 {
3027 foreach ($this->attachment as $attachment) {
3028 if ($attachment[6] == 'inline') {
3029 return true;
3030 }
3031 }
ed546836 3032 return false;
29bf99fd
PS
3033 }
3034
3035 /**
3036 * Check if an attachment (non-inline) is present.
ccff58da 3037 * @return boolean
29bf99fd
PS
3038 */
3039 public function attachmentExists()
3040 {
3041 foreach ($this->attachment as $attachment) {
3042 if ($attachment[6] == 'attachment') {
3043 return true;
3044 }
3045 }
3046 return false;
3047 }
3048
3049 /**
3050 * Check if this message has an alternative body set.
ccff58da 3051 * @return boolean
29bf99fd
PS
3052 */
3053 public function alternativeExists()
3054 {
3055 return !empty($this->AltBody);
3056 }
3057
30f4e2d3
AG
3058 /**
3059 * Clear queued addresses of given kind.
3060 * @access protected
3061 * @param string $kind 'to', 'cc', or 'bcc'
3062 * @return void
3063 */
3064 public function clearQueuedAddresses($kind)
3065 {
3066 $RecipientsQueue = $this->RecipientsQueue;
3067 foreach ($RecipientsQueue as $address => $params) {
3068 if ($params[0] == $kind) {
3069 unset($this->RecipientsQueue[$address]);
3070 }
3071 }
3072 }
3073
29bf99fd
PS
3074 /**
3075 * Clear all To recipients.
3076 * @return void
3077 */
3078 public function clearAddresses()
3079 {
3080 foreach ($this->to as $to) {
3081 unset($this->all_recipients[strtolower($to[0])]);
3082 }
3083 $this->to = array();
30f4e2d3 3084 $this->clearQueuedAddresses('to');
29bf99fd
PS
3085 }
3086
3087 /**
3088 * Clear all CC recipients.
3089 * @return void
3090 */
3091 public function clearCCs()
3092 {
3093 foreach ($this->cc as $cc) {
3094 unset($this->all_recipients[strtolower($cc[0])]);
3095 }
3096 $this->cc = array();
30f4e2d3 3097 $this->clearQueuedAddresses('cc');
29bf99fd
PS
3098 }
3099
3100 /**
3101 * Clear all BCC recipients.
3102 * @return void
3103 */
3104 public function clearBCCs()
3105 {
3106 foreach ($this->bcc as $bcc) {
3107 unset($this->all_recipients[strtolower($bcc[0])]);
3108 }
3109 $this->bcc = array();
30f4e2d3 3110 $this->clearQueuedAddresses('bcc');
29bf99fd
PS
3111 }
3112
3113 /**
3114 * Clear all ReplyTo recipients.
3115 * @return void
3116 */
3117 public function clearReplyTos()
3118 {
3119 $this->ReplyTo = array();
30f4e2d3 3120 $this->ReplyToQueue = array();
29bf99fd
PS
3121 }
3122
3123 /**
3124 * Clear all recipient types.
3125 * @return void
3126 */
3127 public function clearAllRecipients()
3128 {
3129 $this->to = array();
3130 $this->cc = array();
3131 $this->bcc = array();
3132 $this->all_recipients = array();
30f4e2d3 3133 $this->RecipientsQueue = array();
29bf99fd
PS
3134 }
3135
3136 /**
3137 * Clear all filesystem, string, and binary attachments.
3138 * @return void
3139 */
3140 public function clearAttachments()
3141 {
3142 $this->attachment = array();
3143 }
3144
3145 /**
3146 * Clear all custom headers.
3147 * @return void
3148 */
3149 public function clearCustomHeaders()
3150 {
3151 $this->CustomHeader = array();
3152 }
3153
3154 /**
3155 * Add an error message to the error container.
3156 * @access protected
3157 * @param string $msg
3158 * @return void
3159 */
3160 protected function setError($msg)
3161 {
3162 $this->error_count++;
3163 if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3164 $lasterror = $this->smtp->getError();
ec9e2d04
CB
3165 if (!empty($lasterror['error'])) {
3166 $msg .= $this->lang('smtp_error') . $lasterror['error'];
3167 if (!empty($lasterror['detail'])) {
3168 $msg .= ' Detail: '. $lasterror['detail'];
3169 }
3170 if (!empty($lasterror['smtp_code'])) {
3171 $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3172 }
3173 if (!empty($lasterror['smtp_code_ex'])) {
3174 $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3175 }
29bf99fd
PS
3176 }
3177 }
3178 $this->ErrorInfo = $msg;
3179 }
3180
3181 /**
3182 * Return an RFC 822 formatted date.
3183 * @access public
3184 * @return string
3185 * @static
3186 */
3187 public static function rfcDate()
3188 {
ccff58da
MG
3189 // Set the time zone to whatever the default is to avoid 500 errors
3190 // Will default to UTC if it's not set properly in php.ini
29bf99fd
PS
3191 date_default_timezone_set(@date_default_timezone_get());
3192 return date('D, j M Y H:i:s O');
3193 }
3194
3195 /**
3196 * Get the server hostname.
3197 * Returns 'localhost.localdomain' if unknown.
3198 * @access protected
3199 * @return string
3200 */
3201 protected function serverHostname()
3202 {
ccff58da 3203 $result = 'localhost.localdomain';
29bf99fd
PS
3204 if (!empty($this->Hostname)) {
3205 $result = $this->Hostname;
ccff58da 3206 } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
29bf99fd 3207 $result = $_SERVER['SERVER_NAME'];
ccff58da
MG
3208 } elseif (function_exists('gethostname') && gethostname() !== false) {
3209 $result = gethostname();
3210 } elseif (php_uname('n') !== false) {
3211 $result = php_uname('n');
29bf99fd 3212 }
29bf99fd
PS
3213 return $result;
3214 }
3215
3216 /**
3217 * Get an error message in the current language.
3218 * @access protected
3219 * @param string $key
3220 * @return string
3221 */
3222 protected function lang($key)
3223 {
3224 if (count($this->language) < 1) {
3225 $this->setLanguage('en'); // set the default language
3226 }
3227
ec9e2d04
CB
3228 if (array_key_exists($key, $this->language)) {
3229 if ($key == 'smtp_connect_failed') {
3230 //Include a link to troubleshooting docs on SMTP connection failure
3231 //this is by far the biggest cause of support questions
3232 //but it's usually not PHPMailer's fault.
3233 return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3234 }
29bf99fd
PS
3235 return $this->language[$key];
3236 } else {
ec9e2d04
CB
3237 //Return the key as a fallback
3238 return $key;
29bf99fd
PS
3239 }
3240 }
3241
3242 /**
3243 * Check if an error occurred.
3244 * @access public
ccff58da 3245 * @return boolean True if an error did occur.
29bf99fd
PS
3246 */
3247 public function isError()
3248 {
3249 return ($this->error_count > 0);
3250 }
3251
3252 /**
3253 * Ensure consistent line endings in a string.
3254 * Changes every end of line from CRLF, CR or LF to $this->LE.
3255 * @access public
3256 * @param string $str String to fixEOL
3257 * @return string
3258 */
3259 public function fixEOL($str)
3260 {
3261 // Normalise to \n
3262 $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3263 // Now convert LE as needed
3264 if ($this->LE !== "\n") {