295
306
* The SMTP server timeout in seconds.
307
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
298
public $Timeout = 10;
310
public $Timeout = 300;
301
313
* SMTP class debug output mode.
302
* Options: 0 = off, 1 = commands, 2 = commands and data
314
* Debug output level.
318
* * `2` Data and commands
319
* * `3` As 2 plus connection status
320
* * `4` Low-level data output
304
322
* @see SMTP::$do_debug
306
324
public $SMTPDebug = 0;
309
* The function/method to use for debugging output.
310
* Options: "echo" or "error_log"
327
* How to handle debug output.
329
* * `echo` Output plain-text as-is, appropriate for CLI
330
* * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
331
* * `error_log` Output to error log as configured in php.ini
333
* Alternatively, you can provide a callable expecting two params: a message string and the debug level:
335
* $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
337
* @type string|callable
312
338
* @see SMTP::$Debugoutput
314
public $Debugoutput = "echo";
340
public $Debugoutput = 'echo';
317
343
* Whether to keep SMTP connection open after each message.
318
344
* If this is set to true then to close the connection
319
345
* requires an explicit call to smtpClose().
322
348
public $SMTPKeepAlive = false;
325
351
* Whether to split multiple to addresses into multiple messages
326
352
* or send them all in one message.
329
355
public $SingleTo = false;
332
358
* Storage for addresses when SingleTo is enabled.
334
* @todo This should really not be public
360
* @TODO This should really not be public
336
362
public $SingleToArray = array();
593
636
* @param string $header Additional Header(s)
594
637
* @param string $params Params
595
638
* @access private
598
641
private function mailPassthru($to, $subject, $body, $header, $params)
643
//Check overloading of mail function to avoid double-encoding
644
if (ini_get('mbstring.func_overload') & 1) {
645
$subject = $this->secureHeader($subject);
647
$subject = $this->encodeHeader($this->secureHeader($subject));
600
649
if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
601
$rt = @mail($to, $this->encodeHeader($this->secureHeader($subject)), $body, $header);
650
$result = @mail($to, $subject, $body, $header);
603
$rt = @mail($to, $this->encodeHeader($this->secureHeader($subject)), $body, $header, $params);
652
$result = @mail($to, $subject, $body, $header, $params);
609
658
* Output debugging info via user-defined method.
610
* Only if debug output is enabled.
659
* Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
611
660
* @see PHPMailer::$Debugoutput
612
661
* @see PHPMailer::$SMTPDebug
613
662
* @param string $str
615
664
protected function edebug($str)
617
if (!$this->SMTPDebug) {
666
if ($this->SMTPDebug <= 0) {
669
//Avoid clash with built-in function names
670
if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
671
call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
620
674
switch ($this->Debugoutput) {
621
675
case 'error_log':
676
//Don't output, just log
625
//Cleans up output a bit for a better looking display that's HTML-safe
626
echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, $this->CharSet) . "<br>\n";
680
//Cleans up output a bit for a better looking, HTML-safe output
682
preg_replace('/[\r\n]+/', '', $str),
630
//Just echoes exactly what was received
690
//Normalize line breaks
691
$str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
692
echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
636
701
* Sets message type to HTML or plain.
637
* @param bool $ishtml True for HTML mode.
702
* @param boolean $isHtml True for HTML mode.
640
public function isHTML($ishtml = true)
705
public function isHTML($isHtml = true)
643
708
$this->ContentType = 'text/html';
645
710
$this->ContentType = 'text/plain';
825
898
* Check that a string looks like an email address.
826
899
* @param string $address The email address to check
827
900
* @param string $patternselect A selector for the validation pattern to use :
828
* 'auto' - pick best one automatically;
829
* 'pcre8' - use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
830
* 'pcre' - use old PCRE implementation;
831
* 'php' - use PHP built-in FILTER_VALIDATE_EMAIL; faster, less thorough;
832
* 'noregex' - super fast, really dumb.
901
* * `auto` Pick strictest one automatically;
902
* * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
903
* * `pcre` Use old PCRE implementation;
904
* * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does not allow 'dotless' domains;
905
* * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
906
* * `noregex` Don't use a regex: super fast, really dumb.
837
911
public static function validateAddress($address, $patternselect = 'auto')
839
if ($patternselect == 'auto') {
843
) { //Check this instead of extension_loaded so it works when that function is disabled
844
if (version_compare(PCRE_VERSION, '8.0') >= 0) {
913
if (!$patternselect or $patternselect == 'auto') {
914
//Check this constant first so it works when extension_loaded() is disabled by safe mode
915
//Constant was added in PHP 5.2.4
916
if (defined('PCRE_VERSION')) {
917
//This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
918
if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
845
919
$patternselect = 'pcre8';
847
921
$patternselect = 'pcre';
923
} elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
924
//Fall back to older PCRE
925
$patternselect = 'pcre';
850
927
//Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
851
928
if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1036
1125
* @see PHPMailer::$Sendmail
1037
1126
* @throws phpmailerException
1038
1127
* @access protected
1041
1130
protected function sendmailSend($header, $body)
1043
1132
if ($this->Sender != '') {
1044
$sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1133
if ($this->Mailer == 'qmail') {
1134
$sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1136
$sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1046
$sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
1139
if ($this->Mailer == 'qmail') {
1140
$sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1142
$sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1048
if ($this->SingleTo === true) {
1049
foreach ($this->SingleToArray as $val) {
1145
if ($this->SingleTo) {
1146
foreach ($this->SingleToArray as $toAddr) {
1050
1147
if (!@$mail = popen($sendmail, 'w')) {
1051
1148
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1053
fputs($mail, "To: " . $val . "\n");
1150
fputs($mail, 'To: ' . $toAddr . "\n");
1054
1151
fputs($mail, $header);
1055
1152
fputs($mail, $body);
1056
1153
$result = pclose($mail);
1057
// implement call back function if it exists
1058
$isSent = ($result == 0) ? 1 : 0;
1059
$this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1060
1163
if ($result != 0) {
1061
1164
throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1085
1186
* @link http://www.php.net/manual/en/book.mail.php
1086
1187
* @throws phpmailerException
1087
1188
* @access protected
1090
1191
protected function mailSend($header, $body)
1092
1193
$toArr = array();
1093
foreach ($this->to as $t) {
1094
$toArr[] = $this->addrFormat($t);
1194
foreach ($this->to as $toaddr) {
1195
$toArr[] = $this->addrFormat($toaddr);
1096
1197
$to = implode(', ', $toArr);
1098
1199
if (empty($this->Sender)) {
1101
$params = sprintf("-f%s", $this->Sender);
1202
$params = sprintf('-f%s', $this->Sender);
1103
1204
if ($this->Sender != '' and !ini_get('safe_mode')) {
1104
1205
$old_from = ini_get('sendmail_from');
1105
1206
ini_set('sendmail_from', $this->Sender);
1108
if ($this->SingleTo === true && count($toArr) > 1) {
1109
foreach ($toArr as $val) {
1110
$rt = $this->mailPassthru($val, $this->Subject, $body, $header, $params);
1111
// implement call back function if it exists
1112
$isSent = ($rt == 1) ? 1 : 0;
1113
$this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1209
if ($this->SingleTo && count($toArr) > 1) {
1210
foreach ($toArr as $toAddr) {
1211
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1212
$this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1116
$rt = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1117
// implement call back function if it exists
1118
$isSent = ($rt == 1) ? 1 : 0;
1119
$this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1215
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1216
$this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1121
1218
if (isset($old_from)) {
1122
1219
ini_set('sendmail_from', $old_from);
1125
1222
throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1151
1248
* @throws phpmailerException
1153
1250
* @access protected
1156
1253
protected function smtpSend($header, $body)
1158
1255
$bad_rcpt = array();
1160
if (!$this->smtpConnect()) {
1256
if (!$this->smtpConnect($this->SMTPOptions)) {
1161
1257
throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1163
$smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
1259
if ('' == $this->Sender) {
1260
$smtp_from = $this->From;
1262
$smtp_from = $this->Sender;
1164
1264
if (!$this->smtp->mail($smtp_from)) {
1165
1265
$this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1166
1266
throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1169
// Attempt to send attach all recipients
1170
foreach ($this->to as $to) {
1171
if (!$this->smtp->recipient($to[0])) {
1172
$bad_rcpt[] = $to[0];
1177
$this->doCallback($isSent, $to[0], '', '', $this->Subject, $body, $this->From);
1179
foreach ($this->cc as $cc) {
1180
if (!$this->smtp->recipient($cc[0])) {
1181
$bad_rcpt[] = $cc[0];
1186
$this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body, $this->From);
1188
foreach ($this->bcc as $bcc) {
1189
if (!$this->smtp->recipient($bcc[0])) {
1190
$bad_rcpt[] = $bcc[0];
1195
$this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body, $this->From);
1269
// Attempt to send to all recipients
1270
foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1271
foreach ($togroup as $to) {
1272
if (!$this->smtp->recipient($to[0])) {
1273
$error = $this->smtp->getError();
1274
$bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1279
$this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1198
if (count($bad_rcpt) > 0) { //Create error message for any bad addresses
1199
throw new phpmailerException($this->lang('recipients_failed') . implode(', ', $bad_rcpt));
1201
if (!$this->smtp->data($header . $body)) {
1283
// Only send the DATA command if we have viable recipients
1284
if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1202
1285
throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1204
if ($this->SMTPKeepAlive == true) {
1287
if ($this->SMTPKeepAlive) {
1205
1288
$this->smtp->reset();
1207
1290
$this->smtp->quit();
1208
1291
$this->smtp->close();
1293
//Create error message for any bad addresses
1294
if (count($bad_rcpt) > 0) {
1296
foreach ($bad_rcpt as $bad) {
1297
$errstr .= $bad['to'] . ': ' . $bad['error'];
1299
throw new phpmailerException(
1300
$this->lang('recipients_failed') . $errstr,
1234
1328
$this->smtp->setDebugLevel($this->SMTPDebug);
1235
1329
$this->smtp->setDebugOutput($this->Debugoutput);
1236
1330
$this->smtp->setVerp($this->do_verp);
1237
$tls = ($this->SMTPSecure == 'tls');
1238
$ssl = ($this->SMTPSecure == 'ssl');
1239
1331
$hosts = explode(';', $this->Host);
1240
1332
$lastexception = null;
1242
1334
foreach ($hosts as $hostentry) {
1243
1335
$hostinfo = array();
1336
if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1337
// Not a valid host entry
1340
// $hostinfo[2]: optional ssl or tls prefix
1341
// $hostinfo[3]: the hostname
1342
// $hostinfo[4]: optional port number
1343
// The host string prefix can temporarily override the current setting for SMTPSecure
1344
// If it's not specified, the default value is used
1346
$secure = $this->SMTPSecure;
1347
$tls = ($this->SMTPSecure == 'tls');
1348
if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1350
$tls = false; // Can't have SSL and TLS at the same time
1352
} elseif ($hostinfo[2] == 'tls') {
1354
// tls doesn't use a prefix
1357
//Do we need the OpenSSL extension?
1358
$sslext = defined('OPENSSL_ALGO_SHA1');
1359
if ('tls' === $secure or 'ssl' === $secure) {
1360
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1362
throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1365
$host = $hostinfo[3];
1245
1366
$port = $this->Port;
1247
'/^(.+):([0-9]+)$/',
1251
) { //If $hostentry contains 'address:port', override default
1252
$host = $hostinfo[1];
1253
$port = $hostinfo[2];
1367
$tport = (integer)$hostinfo[4];
1368
if ($tport > 0 and $tport < 65536) {
1255
if ($this->smtp->connect(($ssl ? 'ssl://' : '') . $host, $port, $this->Timeout, $options)) {
1371
if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1257
1373
if ($this->Helo) {
1258
1374
$hello = $this->Helo;
1406
1542
* Original written by philippe.
1407
1543
* @param string $message The message to wrap
1408
1544
* @param integer $length The line length to wrap to
1409
* @param bool $qp_mode Whether to run in Quoted-Printable mode
1545
* @param boolean $qp_mode Whether to run in Quoted-Printable mode
1410
1546
* @access public
1411
1547
* @return string
1413
1549
public function wrapText($message, $length, $qp_mode = false)
1415
$soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
1552
$soft_break = sprintf(' =%s', $this->LE);
1554
$soft_break = $this->LE;
1416
1556
// If utf-8 encoding is used, we will need to make sure we don't
1417
1557
// split multibyte characters when we wrap
1418
$is_utf8 = (strtolower($this->CharSet) == "utf-8");
1558
$is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1419
1559
$lelen = strlen($this->LE);
1420
1560
$crlflen = strlen(self::CRLF);
1422
1562
$message = $this->fixEOL($message);
1563
//Remove a trailing line break
1423
1564
if (substr($message, -$lelen) == $this->LE) {
1424
1565
$message = substr($message, 0, -$lelen);
1427
$line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE
1568
//Split message into lines
1569
$lines = explode($this->LE, $message);
1570
//Message will be rebuilt in here
1429
for ($i = 0; $i < count($line); $i++) {
1430
$line_part = explode(' ', $line[$i]);
1572
foreach ($lines as $line) {
1573
$words = explode(' ', $line);
1432
for ($e = 0; $e < count($line_part); $e++) {
1433
$word = $line_part[$e];
1576
foreach ($words as $word) {
1434
1577
if ($qp_mode and (strlen($word) > $length)) {
1435
1578
$space_left = $length - strlen($buf) - $crlflen;
1437
1580
if ($space_left > 20) {
1438
1581
$len = $space_left;
1439
1582
if ($is_utf8) {
1440
1583
$len = $this->utf8CharBoundary($word, $len);
1441
} elseif (substr($word, $len - 1, 1) == "=") {
1584
} elseif (substr($word, $len - 1, 1) == '=') {
1443
} elseif (substr($word, $len - 2, 1) == "=") {
1586
} elseif (substr($word, $len - 2, 1) == '=') {
1446
1589
$part = substr($word, 0, $len);
1447
1590
$word = substr($word, $len);
1448
1591
$buf .= ' ' . $part;
1449
$message .= $buf . sprintf("=%s", self::CRLF);
1592
$message .= $buf . sprintf('=%s', self::CRLF);
1451
1594
$message .= $buf . $soft_break;
1568
// Set the boundaries
1569
$uniq_id = md5(uniqid(time()));
1570
$this->boundary[1] = 'b1_' . $uniq_id;
1571
$this->boundary[2] = 'b2_' . $uniq_id;
1572
$this->boundary[3] = 'b3_' . $uniq_id;
1574
1721
if ($this->MessageDate == '') {
1575
$result .= $this->headerLine('Date', self::rfcDate());
1577
$result .= $this->headerLine('Date', $this->MessageDate);
1722
$this->MessageDate = self::rfcDate();
1724
$result .= $this->headerLine('Date', $this->MessageDate);
1580
if ($this->ReturnPath) {
1581
$result .= $this->headerLine('Return-Path', '<' . trim($this->ReturnPath) . '>');
1582
} elseif ($this->Sender == '') {
1583
$result .= $this->headerLine('Return-Path', '<' . trim($this->From) . '>');
1585
$result .= $this->headerLine('Return-Path', '<' . trim($this->Sender) . '>');
1588
1727
// To be created automatically by mail()
1589
if ($this->Mailer != 'mail') {
1590
if ($this->SingleTo === true) {
1591
foreach ($this->to as $t) {
1592
$this->SingleToArray[] = $this->addrFormat($t);
1728
if ($this->SingleTo) {
1729
if ($this->Mailer != 'mail') {
1730
foreach ($this->to as $toaddr) {
1731
$this->SingleToArray[] = $this->addrFormat($toaddr);
1595
if (count($this->to) > 0) {
1735
if (count($this->to) > 0) {
1736
if ($this->Mailer != 'mail') {
1596
1737
$result .= $this->addrAppend('To', $this->to);
1597
} elseif (count($this->cc) == 0) {
1598
$result .= $this->headerLine('To', 'undisclosed-recipients:;');
1739
} elseif (count($this->cc) == 0) {
1740
$result .= $this->headerLine('To', 'undisclosed-recipients:;');
1733
1892
$this->setWordWrap();
1894
$bodyEncoding = $this->Encoding;
1895
$bodyCharSet = $this->CharSet;
1896
//Can we do a 7-bit downgrade?
1897
if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
1898
$bodyEncoding = '7bit';
1899
$bodyCharSet = 'us-ascii';
1901
//If lines are too long, change to quoted-printable transfer encoding
1902
if (self::hasLineLongerThanMax($this->Body)) {
1903
$this->Encoding = 'quoted-printable';
1904
$bodyEncoding = 'quoted-printable';
1907
$altBodyEncoding = $this->Encoding;
1908
$altBodyCharSet = $this->CharSet;
1909
//Can we do a 7-bit downgrade?
1910
if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
1911
$altBodyEncoding = '7bit';
1912
$altBodyCharSet = 'us-ascii';
1914
//If lines are too long, change to quoted-printable transfer encoding
1915
if (self::hasLineLongerThanMax($this->AltBody)) {
1916
$altBodyEncoding = 'quoted-printable';
1918
//Use this as a preamble in all multipart message types
1919
$mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
1735
1920
switch ($this->message_type) {
1737
$body .= $this->getBoundary($this->boundary[1], '', '', '');
1738
$body .= $this->encodeString($this->Body, $this->Encoding);
1923
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
1924
$body .= $this->encodeString($this->Body, $bodyEncoding);
1739
1925
$body .= $this->LE . $this->LE;
1740
1926
$body .= $this->attachAll('inline', $this->boundary[1]);
1743
$body .= $this->getBoundary($this->boundary[1], '', '', '');
1744
$body .= $this->encodeString($this->Body, $this->Encoding);
1930
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
1931
$body .= $this->encodeString($this->Body, $bodyEncoding);
1745
1932
$body .= $this->LE . $this->LE;
1746
1933
$body .= $this->attachAll('attachment', $this->boundary[1]);
1748
1935
case 'inline_attach':
1749
1937
$body .= $this->textLine('--' . $this->boundary[1]);
1750
1938
$body .= $this->headerLine('Content-Type', 'multipart/related;');
1751
1939
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1752
1940
$body .= $this->LE;
1753
$body .= $this->getBoundary($this->boundary[2], '', '', '');
1754
$body .= $this->encodeString($this->Body, $this->Encoding);
1941
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
1942
$body .= $this->encodeString($this->Body, $bodyEncoding);
1755
1943
$body .= $this->LE . $this->LE;
1756
1944
$body .= $this->attachAll('inline', $this->boundary[2]);
1757
1945
$body .= $this->LE;
1758
1946
$body .= $this->attachAll('attachment', $this->boundary[1]);
1761
$body .= $this->getBoundary($this->boundary[1], '', 'text/plain', '');
1762
$body .= $this->encodeString($this->AltBody, $this->Encoding);
1950
$body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1951
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1763
1952
$body .= $this->LE . $this->LE;
1764
$body .= $this->getBoundary($this->boundary[1], '', 'text/html', '');
1765
$body .= $this->encodeString($this->Body, $this->Encoding);
1953
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
1954
$body .= $this->encodeString($this->Body, $bodyEncoding);
1766
1955
$body .= $this->LE . $this->LE;
1767
1956
if (!empty($this->Ical)) {
1768
1957
$body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
1772
1961
$body .= $this->endBoundary($this->boundary[1]);
1774
1963
case 'alt_inline':
1775
$body .= $this->getBoundary($this->boundary[1], '', 'text/plain', '');
1776
$body .= $this->encodeString($this->AltBody, $this->Encoding);
1965
$body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1966
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1777
1967
$body .= $this->LE . $this->LE;
1778
1968
$body .= $this->textLine('--' . $this->boundary[1]);
1779
1969
$body .= $this->headerLine('Content-Type', 'multipart/related;');
1780
1970
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1781
1971
$body .= $this->LE;
1782
$body .= $this->getBoundary($this->boundary[2], '', 'text/html', '');
1783
$body .= $this->encodeString($this->Body, $this->Encoding);
1972
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
1973
$body .= $this->encodeString($this->Body, $bodyEncoding);
1784
1974
$body .= $this->LE . $this->LE;
1785
1975
$body .= $this->attachAll('inline', $this->boundary[2]);
1786
1976
$body .= $this->LE;
1787
1977
$body .= $this->endBoundary($this->boundary[1]);
1789
1979
case 'alt_attach':
1790
1981
$body .= $this->textLine('--' . $this->boundary[1]);
1791
1982
$body .= $this->headerLine('Content-Type', 'multipart/alternative;');
1792
1983
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1793
1984
$body .= $this->LE;
1794
$body .= $this->getBoundary($this->boundary[2], '', 'text/plain', '');
1795
$body .= $this->encodeString($this->AltBody, $this->Encoding);
1985
$body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1986
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1796
1987
$body .= $this->LE . $this->LE;
1797
$body .= $this->getBoundary($this->boundary[2], '', 'text/html', '');
1798
$body .= $this->encodeString($this->Body, $this->Encoding);
1988
$body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
1989
$body .= $this->encodeString($this->Body, $bodyEncoding);
1799
1990
$body .= $this->LE . $this->LE;
1800
1991
$body .= $this->endBoundary($this->boundary[2]);
1801
1992
$body .= $this->LE;
1802
1993
$body .= $this->attachAll('attachment', $this->boundary[1]);
1804
1995
case 'alt_inline_attach':
1805
1997
$body .= $this->textLine('--' . $this->boundary[1]);
1806
1998
$body .= $this->headerLine('Content-Type', 'multipart/alternative;');
1807
1999
$body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1808
2000
$body .= $this->LE;
1809
$body .= $this->getBoundary($this->boundary[2], '', 'text/plain', '');
1810
$body .= $this->encodeString($this->AltBody, $this->Encoding);
2001
$body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2002
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1811
2003
$body .= $this->LE . $this->LE;
1812
2004
$body .= $this->textLine('--' . $this->boundary[2]);
1813
2005
$body .= $this->headerLine('Content-Type', 'multipart/related;');
1814
2006
$body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
1815
2007
$body .= $this->LE;
1816
$body .= $this->getBoundary($this->boundary[3], '', 'text/html', '');
1817
$body .= $this->encodeString($this->Body, $this->Encoding);
2008
$body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2009
$body .= $this->encodeString($this->Body, $bodyEncoding);
1818
2010
$body .= $this->LE . $this->LE;
1819
2011
$body .= $this->attachAll('inline', $this->boundary[3]);
1820
2012
$body .= $this->LE;
1833
2025
} elseif ($this->sign_key_file) {
1835
2027
if (!defined('PKCS7_TEXT')) {
1836
throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
2028
throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2030
// @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
1838
2031
$file = tempnam(sys_get_temp_dir(), 'mail');
1839
file_put_contents($file, $body); //TODO check this worked
2032
if (false === file_put_contents($file, $body)) {
2033
throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
1840
2035
$signed = tempnam(sys_get_temp_dir(), 'signed');
1841
if (@openssl_pkcs7_sign(
1844
'file://' . realpath($this->sign_cert_file),
1845
array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2036
//Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2037
if (empty($this->sign_extracerts_file)) {
2038
$sign = @openssl_pkcs7_sign(
2041
'file://' . realpath($this->sign_cert_file),
2042
array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2046
$sign = @openssl_pkcs7_sign(
2049
'file://' . realpath($this->sign_cert_file),
2050
array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2053
$this->sign_extracerts_file
1849
2057
@unlink($file);
1850
2058
$body = file_get_contents($signed);
1851
2059
@unlink($signed);
2060
//The message returned by openssl contains both headers and body, so need to split them up
2061
$parts = explode("\n\n", $body, 2);
2062
$this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
1853
2065
@unlink($file);
1854
2066
@unlink($signed);
1855
2067
throw new phpmailerException($this->lang('signing') . openssl_error_string());
1857
} catch (phpmailerException $e) {
2069
} catch (phpmailerException $exc) {
1859
2071
if ($this->exceptions) {
2366
2601
public function encodeQ($str, $position = 'text')
2368
//There should not be any EOL in the string
2603
// There should not be any EOL in the string
2370
2605
$encoded = str_replace(array("\r", "\n"), '', $str);
2371
2606
switch (strtolower($position)) {
2373
//RFC 2047 section 5.3
2608
// RFC 2047 section 5.3
2374
2609
$pattern = '^A-Za-z0-9!*+\/ -';
2376
2611
/** @noinspection PhpMissingBreakStatementInspection */
2377
2612
case 'comment':
2378
//RFC 2047 section 5.2
2613
// RFC 2047 section 5.2
2379
2614
$pattern = '\(\)"';
2380
//intentional fall-through
2381
//for this reason we build the $pattern without including delimiters and []
2615
// intentional fall-through
2616
// for this reason we build the $pattern without including delimiters and []
2384
//RFC 2047 section 5.1
2385
//Replace every high ascii, control, =, ? and _ characters
2619
// RFC 2047 section 5.1
2620
// Replace every high ascii, control, =, ? and _ characters
2386
2621
$pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2389
2624
$matches = array();
2390
2625
if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2391
//If the string contains an '=', make sure it's the first thing we replace
2392
//so as to avoid double-encoding
2393
$s = array_search('=', $matches[0]);
2395
unset($matches[0][$s]);
2626
// If the string contains an '=', make sure it's the first thing we replace
2627
// so as to avoid double-encoding
2628
$eqkey = array_search('=', $matches[0]);
2629
if (false !== $eqkey) {
2630
unset($matches[0][$eqkey]);
2396
2631
array_unshift($matches[0], '=');
2398
2633
foreach (array_unique($matches[0]) as $char) {
2399
2634
$encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2402
//Replace every spaces to _ (more readable than =20)
2637
// Replace every spaces to _ (more readable than =20)
2403
2638
return str_replace(' ', '_', $encoded);
2765
3028
* @access public
2766
3029
* @param string $message HTML message string
2767
3030
* @param string $basedir baseline directory for path
2768
* @param bool $advanced Whether to use the advanced HTML to text converter
3031
* @param boolean|callable $advanced Whether to use the internal HTML to text converter
3032
* or your own custom converter @see html2text()
2769
3033
* @return string $message
2771
3035
public function msgHTML($message, $basedir = '', $advanced = false)
2773
preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
3037
preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
2774
3038
if (isset($images[2])) {
2775
foreach ($images[2] as $i => $url) {
2776
// do not change urls for absolute images (thanks to corvuscorax)
2777
if (!preg_match('#^[A-z]+://#', $url)) {
3039
foreach ($images[2] as $imgindex => $url) {
3040
// Convert data URIs into embedded images
3041
if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3042
$data = substr($url, strpos($url, ','));
3044
$data = base64_decode($data);
3046
$data = rawurldecode($data);
3048
$cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3049
if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
3050
$message = str_replace(
3051
$images[0][$imgindex],
3052
$images[1][$imgindex] . '="cid:' . $cid . '"',
3056
} elseif (!preg_match('#^[A-z]+://#', $url)) {
3057
// Do not change urls for absolute images (thanks to corvuscorax)
2778
3058
$filename = basename($url);
2779
3059
$directory = dirname($url);
2780
3060
if ($directory == '.') {
2781
3061
$directory = '';
2783
$cid = md5($url) . '@phpmailer.0'; //RFC2392 S 2
3063
$cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
2784
3064
if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
2785
3065
$basedir .= '/';
2807
3087
$this->isHTML(true);
2808
if (empty($this->AltBody)) {
2809
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
2811
//Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3088
// Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
2812
3089
$this->Body = $this->normalizeBreaks($message);
2813
3090
$this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3091
if (empty($this->AltBody)) {
3092
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3093
self::CRLF . self::CRLF;
2814
3095
return $this->Body;
2818
3099
* Convert an HTML string into plain text.
3100
* This is used by msgHTML().
3101
* Note - older versions of this function used a bundled advanced converter
3102
* which was been removed for license reasons in #232
3105
* // Use default conversion
3106
* $plain = $mail->html2text($html);
3107
* // Use your own custom converter
3108
* $plain = $mail->html2text($html, function($html) {
3109
* $converter = new MyHtml2text($html);
3110
* return $converter->get_text();
2819
3113
* @param string $html The HTML text to convert
2820
* @param bool $advanced Should this use the more complex html2text converter or just a simple one?
3114
* @param boolean|callable $advanced Any boolean value to use the internal converter,
3115
* or provide your own callable for custom conversion.
2821
3116
* @return string
2823
3118
public function html2text($html, $advanced = false)
2826
require_once 'extras/class.html2text.php';
2827
$h = new html2text($html);
2828
return $h->get_text();
3120
if (is_callable($advanced)) {
3121
return call_user_func($advanced, $html);
2830
3123
return html_entity_decode(
2831
3124
trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
2844
3137
public static function _mime_types($ext = '')
2846
3139
$mimes = array(
2847
'xl' => 'application/excel',
2848
'hqx' => 'application/mac-binhex40',
2849
'cpt' => 'application/mac-compactpro',
2850
'bin' => 'application/macbinary',
2851
'doc' => 'application/msword',
2852
'word' => 'application/msword',
3140
'xl' => 'application/excel',
3141
'js' => 'application/javascript',
3142
'hqx' => 'application/mac-binhex40',
3143
'cpt' => 'application/mac-compactpro',
3144
'bin' => 'application/macbinary',
3145
'doc' => 'application/msword',
3146
'word' => 'application/msword',
2853
3147
'class' => 'application/octet-stream',
2854
'dll' => 'application/octet-stream',
2855
'dms' => 'application/octet-stream',
2856
'exe' => 'application/octet-stream',
2857
'lha' => 'application/octet-stream',
2858
'lzh' => 'application/octet-stream',
2859
'psd' => 'application/octet-stream',
2860
'sea' => 'application/octet-stream',
2861
'so' => 'application/octet-stream',
2862
'oda' => 'application/oda',
2863
'pdf' => 'application/pdf',
2864
'ai' => 'application/postscript',
2865
'eps' => 'application/postscript',
2866
'ps' => 'application/postscript',
2867
'smi' => 'application/smil',
2868
'smil' => 'application/smil',
2869
'mif' => 'application/vnd.mif',
2870
'xls' => 'application/vnd.ms-excel',
2871
'ppt' => 'application/vnd.ms-powerpoint',
3148
'dll' => 'application/octet-stream',
3149
'dms' => 'application/octet-stream',
3150
'exe' => 'application/octet-stream',
3151
'lha' => 'application/octet-stream',
3152
'lzh' => 'application/octet-stream',
3153
'psd' => 'application/octet-stream',
3154
'sea' => 'application/octet-stream',
3155
'so' => 'application/octet-stream',
3156
'oda' => 'application/oda',
3157
'pdf' => 'application/pdf',
3158
'ai' => 'application/postscript',
3159
'eps' => 'application/postscript',
3160
'ps' => 'application/postscript',
3161
'smi' => 'application/smil',
3162
'smil' => 'application/smil',
3163
'mif' => 'application/vnd.mif',
3164
'xls' => 'application/vnd.ms-excel',
3165
'ppt' => 'application/vnd.ms-powerpoint',
2872
3166
'wbxml' => 'application/vnd.wap.wbxml',
2873
'wmlc' => 'application/vnd.wap.wmlc',
2874
'dcr' => 'application/x-director',
2875
'dir' => 'application/x-director',
2876
'dxr' => 'application/x-director',
2877
'dvi' => 'application/x-dvi',
2878
'gtar' => 'application/x-gtar',
2879
'php3' => 'application/x-httpd-php',
2880
'php4' => 'application/x-httpd-php',
2881
'php' => 'application/x-httpd-php',
3167
'wmlc' => 'application/vnd.wap.wmlc',
3168
'dcr' => 'application/x-director',
3169
'dir' => 'application/x-director',
3170
'dxr' => 'application/x-director',
3171
'dvi' => 'application/x-dvi',
3172
'gtar' => 'application/x-gtar',
3173
'php3' => 'application/x-httpd-php',
3174
'php4' => 'application/x-httpd-php',
3175
'php' => 'application/x-httpd-php',
2882
3176
'phtml' => 'application/x-httpd-php',
2883
'phps' => 'application/x-httpd-php-source',
2884
'js' => 'application/x-javascript',
2885
'swf' => 'application/x-shockwave-flash',
2886
'sit' => 'application/x-stuffit',
2887
'tar' => 'application/x-tar',
2888
'tgz' => 'application/x-tar',
2889
'xht' => 'application/xhtml+xml',
3177
'phps' => 'application/x-httpd-php-source',
3178
'swf' => 'application/x-shockwave-flash',
3179
'sit' => 'application/x-stuffit',
3180
'tar' => 'application/x-tar',
3181
'tgz' => 'application/x-tar',
3182
'xht' => 'application/xhtml+xml',
2890
3183
'xhtml' => 'application/xhtml+xml',
2891
'zip' => 'application/zip',
2892
'mid' => 'audio/midi',
2893
'midi' => 'audio/midi',
2894
'mp2' => 'audio/mpeg',
2895
'mp3' => 'audio/mpeg',
2896
'mpga' => 'audio/mpeg',
2897
'aif' => 'audio/x-aiff',
2898
'aifc' => 'audio/x-aiff',
2899
'aiff' => 'audio/x-aiff',
2900
'ram' => 'audio/x-pn-realaudio',
2901
'rm' => 'audio/x-pn-realaudio',
2902
'rpm' => 'audio/x-pn-realaudio-plugin',
2903
'ra' => 'audio/x-realaudio',
2904
'wav' => 'audio/x-wav',
2905
'bmp' => 'image/bmp',
2906
'gif' => 'image/gif',
2907
'jpeg' => 'image/jpeg',
2908
'jpe' => 'image/jpeg',
2909
'jpg' => 'image/jpeg',
2910
'png' => 'image/png',
2911
'tiff' => 'image/tiff',
2912
'tif' => 'image/tiff',
2913
'eml' => 'message/rfc822',
2914
'css' => 'text/css',
2915
'html' => 'text/html',
2916
'htm' => 'text/html',
3184
'zip' => 'application/zip',
3185
'mid' => 'audio/midi',
3186
'midi' => 'audio/midi',
3187
'mp2' => 'audio/mpeg',
3188
'mp3' => 'audio/mpeg',
3189
'mpga' => 'audio/mpeg',
3190
'aif' => 'audio/x-aiff',
3191
'aifc' => 'audio/x-aiff',
3192
'aiff' => 'audio/x-aiff',
3193
'ram' => 'audio/x-pn-realaudio',
3194
'rm' => 'audio/x-pn-realaudio',
3195
'rpm' => 'audio/x-pn-realaudio-plugin',
3196
'ra' => 'audio/x-realaudio',
3197
'wav' => 'audio/x-wav',
3198
'bmp' => 'image/bmp',
3199
'gif' => 'image/gif',
3200
'jpeg' => 'image/jpeg',
3201
'jpe' => 'image/jpeg',
3202
'jpg' => 'image/jpeg',
3203
'png' => 'image/png',
3204
'tiff' => 'image/tiff',
3205
'tif' => 'image/tiff',
3206
'eml' => 'message/rfc822',
3207
'css' => 'text/css',
3208
'html' => 'text/html',
3209
'htm' => 'text/html',
2917
3210
'shtml' => 'text/html',
2918
'log' => 'text/plain',
2919
'text' => 'text/plain',
2920
'txt' => 'text/plain',
2921
'rtx' => 'text/richtext',
2922
'rtf' => 'text/rtf',
2923
'xml' => 'text/xml',
2924
'xsl' => 'text/xml',
2925
'mpeg' => 'video/mpeg',
2926
'mpe' => 'video/mpeg',
2927
'mpg' => 'video/mpeg',
2928
'mov' => 'video/quicktime',
2929
'qt' => 'video/quicktime',
2930
'rv' => 'video/vnd.rn-realvideo',
2931
'avi' => 'video/x-msvideo',
3211
'log' => 'text/plain',
3212
'text' => 'text/plain',
3213
'txt' => 'text/plain',
3214
'rtx' => 'text/richtext',
3215
'rtf' => 'text/rtf',
3216
'vcf' => 'text/vcard',
3217
'vcard' => 'text/vcard',
3218
'xml' => 'text/xml',
3219
'xsl' => 'text/xml',
3220
'mpeg' => 'video/mpeg',
3221
'mpe' => 'video/mpeg',
3222
'mpg' => 'video/mpeg',
3223
'mov' => 'video/quicktime',
3224
'qt' => 'video/quicktime',
3225
'rv' => 'video/vnd.rn-realvideo',
3226
'avi' => 'video/x-msvideo',
2932
3227
'movie' => 'video/x-sgi-movie'
2934
return (array_key_exists(strtolower($ext), $mimes) ? $mimes[strtolower($ext)]: 'application/octet-stream');
3229
if (array_key_exists(strtolower($ext), $mimes)) {
3230
return $mimes[strtolower($ext)];
3232
return 'application/octet-stream';