",
* as defined in RFC5322 section 3.6.4 or it will be ignored.
*
* @see https://tools.ietf.org/html/rfc5322#section-3.6.4
*
* @var string
*/
public $MessageID = '';
/**
* The message Date to be used in the Date header.
* If empty, the current date will be added.
*
* @var string
*/
public $MessageDate = '';
/**
* SMTP hosts.
* Either a single hostname or multiple semicolon-delimited hostnames.
* You can also specify a different port
* for each host by using this format: [hostname:port]
* (e.g. "smtp1.example.com:25;smtp2.example.com").
* You can also specify encryption type, for example:
* (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
* Hosts will be tried in order.
*
* @var string
*/
public $Host = 'localhost';
/**
* The default SMTP server port.
*
* @var int
*/
public $Port = 25;
/**
* The SMTP HELO/EHLO name used for the SMTP connection.
* Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
* one with the same method described above for $Hostname.
*
* @see PHPMailer::$Hostname
*
* @var string
*/
public $Helo = '';
/**
* What kind of encryption to use on the SMTP connection.
* Options: '', static::ENCRYPTION_STARTTLS, or static::ENCRYPTION_SMTPS.
*
* @var string
*/
public $SMTPSecure = '';
/**
* Whether to enable TLS encryption automatically if a server supports it,
* even if `SMTPSecure` is not set to 'tls'.
* Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
*
* @var bool
*/
public $SMTPAutoTLS = true;
/**
* Whether to use SMTP authentication.
* Uses the Username and Password properties.
*
* @see PHPMailer::$Username
* @see PHPMailer::$Password
*
* @var bool
*/
public $SMTPAuth = false;
/**
* Options array passed to stream_context_create when connecting via SMTP.
*
* @var array
*/
public $SMTPOptions = [];
/**
* SMTP username.
*
* @var string
*/
public $Username = '';
/**
* SMTP password.
*
* @var string
*/
public $Password = '';
/**
* SMTP authentication type. Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2.
* If not specified, the first one from that list that the server supports will be selected.
*
* @var string
*/
public $AuthType = '';
/**
* An implementation of the PHPMailer OAuthTokenProvider interface.
*
* @var OAuthTokenProvider
*/
protected $oauth;
/**
* The SMTP server timeout in seconds.
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2.
*
* @var int
*/
public $Timeout = 300;
/**
* Comma separated list of DSN notifications
* 'NEVER' under no circumstances a DSN must be returned to the sender.
* If you use NEVER all other notifications will be ignored.
* 'SUCCESS' will notify you when your mail has arrived at its destination.
* 'FAILURE' will arrive if an error occurred during delivery.
* 'DELAY' will notify you if there is an unusual delay in delivery, but the actual
* delivery's outcome (success or failure) is not yet decided.
*
* @see https://tools.ietf.org/html/rfc3461 See section 4.1 for more information about NOTIFY
*/
public $dsn = '';
/**
* SMTP class debug output mode.
* Debug output level.
* Options:
* @see SMTP::DEBUG_OFF: No output
* @see SMTP::DEBUG_CLIENT: Client messages
* @see SMTP::DEBUG_SERVER: Client and server messages
* @see SMTP::DEBUG_CONNECTION: As SERVER plus connection status
* @see SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed
*
* @see SMTP::$do_debug
*
* @var int
*/
public $SMTPDebug = 0;
/**
* How to handle debug output.
* Options:
* * `echo` Output plain-text as-is, appropriate for CLI
* * `html` Output escaped, line breaks converted to `
`, appropriate for browser output
* * `error_log` Output to error log as configured in php.ini
* By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise.
* Alternatively, you can provide a callable expecting two params: a message string and the debug level:
*
* ```php
* $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
* ```
*
* Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug`
* level output is used:
*
* ```php
* $mail->Debugoutput = new myPsr3Logger;
* ```
*
* @see SMTP::$Debugoutput
*
* @var string|callable|\Psr\Log\LoggerInterface
*/
public $Debugoutput = 'echo';
/**
* Whether to keep the SMTP connection open after each message.
* If this is set to true then the connection will remain open after a send,
* and closing the connection will require an explicit call to smtpClose().
* It's a good idea to use this if you are sending multiple messages as it reduces overhead.
* See the mailing list example for how to use it.
*
* @var bool
*/
public $SMTPKeepAlive = false;
/**
* Whether to split multiple to addresses into multiple messages
* or send them all in one message.
* Only supported in `mail` and `sendmail` transports, not in SMTP.
*
* @var bool
*
* @deprecated 6.0.0 PHPMailer isn't a mailing list manager!
*/
public $SingleTo = false;
/**
* Storage for addresses when SingleTo is enabled.
*
* @var array
*/
protected $SingleToArray = [];
/**
* Whether to generate VERP addresses on send.
* Only applicable when sending via SMTP.
*
* @see https://en.wikipedia.org/wiki/Variable_envelope_return_path
* @see http://www.postfix.org/VERP_README.html Postfix VERP info
*
* @var bool
*/
public $do_verp = false;
/**
* Whether to allow sending messages with an empty body.
*
* @var bool
*/
public $AllowEmpty = false;
/**
* DKIM selector.
*
* @var string
*/
public $DKIM_selector = '';
/**
* DKIM Identity.
* Usually the email address used as the source of the email.
*
* @var string
*/
public $DKIM_identity = '';
/**
* DKIM passphrase.
* Used if your key is encrypted.
*
* @var string
*/
public $DKIM_passphrase = '';
/**
* DKIM signing domain name.
*
* @example 'example.com'
*
* @var string
*/
public $DKIM_domain = '';
/**
* DKIM Copy header field values for diagnostic use.
*
* @var bool
*/
public $DKIM_copyHeaderFields = true;
/**
* DKIM Extra signing headers.
*
* @example ['List-Unsubscribe', 'List-Help']
*
* @var array
*/
public $DKIM_extraHeaders = [];
/**
* DKIM private key file path.
*
* @var string
*/
public $DKIM_private = '';
/**
* DKIM private key string.
*
* If set, takes precedence over `$DKIM_private`.
*
* @var string
*/
public $DKIM_private_string = '';
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* Value can be any php callable: http://www.php.net/is_callable
*
* Parameters:
* bool $result result of the send action
* array $to email addresses of the recipients
* array $cc cc email addresses
* array $bcc bcc email addresses
* string $subject the subject
* string $body the email body
* string $from email address of sender
* string $extra extra information of possible use
* "smtp_transaction_id' => last smtp transaction id
*
* @var string
*/
public $action_function = '';
/**
* What to put in the X-Mailer header.
* Options: An empty string for PHPMailer default, whitespace/null for none, or a string to use.
*
* @var string|null
*/
public $XMailer = '';
/**
* Which validator to use by default when validating email addresses.
* May be a callable to inject your own validator, but there are several built-in validators.
* The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option.
*
* @see PHPMailer::validateAddress()
*
* @var string|callable
*/
public static $validator = 'php';
/**
* An instance of the SMTP sender class.
*
* @var SMTP
*/
protected $smtp;
/**
* The array of 'to' names and addresses.
*
* @var array
*/
protected $to = [];
/**
* The array of 'cc' names and addresses.
*
* @var array
*/
protected $cc = [];
/**
* The array of 'bcc' names and addresses.
*
* @var array
*/
protected $bcc = [];
/**
* The array of reply-to names and addresses.
*
* @var array
*/
protected $ReplyTo = [];
/**
* An array of all kinds of addresses.
* Includes all of $to, $cc, $bcc.
*
* @see PHPMailer::$to
* @see PHPMailer::$cc
* @see PHPMailer::$bcc
*
* @var array
*/
protected $all_recipients = [];
/**
* An array of names and addresses queued for validation.
* In send(), valid and non duplicate entries are moved to $all_recipients
* and one of $to, $cc, or $bcc.
* This array is used only for addresses with IDN.
*
* @see PHPMailer::$to
* @see PHPMailer::$cc
* @see PHPMailer::$bcc
* @see PHPMailer::$all_recipients
*
* @var array
*/
protected $RecipientsQueue = [];
/**
* An array of reply-to names and addresses queued for validation.
* In send(), valid and non duplicate entries are moved to $ReplyTo.
* This array is used only for addresses with IDN.
*
* @see PHPMailer::$ReplyTo
*
* @var array
*/
protected $ReplyToQueue = [];
/**
* The array of attachments.
*
* @var array
*/
protected $attachment = [];
/**
* The array of custom headers.
*
* @var array
*/
protected $CustomHeader = [];
/**
* The most recent Message-ID (including angular brackets).
*
* @var string
*/
protected $lastMessageID = '';
/**
* The message's MIME type.
*
* @var string
*/
protected $message_type = '';
/**
* The array of MIME boundary strings.
*
* @var array
*/
protected $boundary = [];
/**
* The array of available text strings for the current language.
*
* @var array
*/
protected $language = [];
/**
* The number of errors encountered.
*
* @var int
*/
protected $error_count = 0;
/**
* The S/MIME certificate file path.
*
* @var string
*/
protected $sign_cert_file = '';
/**
* The S/MIME key file path.
*
* @var string
*/
protected $sign_key_file = '';
/**
* The optional S/MIME extra certificates ("CA Chain") file path.
*
* @var string
*/
protected $sign_extracerts_file = '';
/**
* The S/MIME password for the key.
* Used only if the key is encrypted.
*
* @var string
*/
protected $sign_key_pass = '';
/**
* Whether to throw exceptions for errors.
*
* @var bool
*/
protected $exceptions = false;
/**
* Unique ID used for message ID and boundaries.
*
* @var string
*/
protected $uniqueid = '';
/**
* The PHPMailer Version number.
*
* @var string
*/
const VERSION = '6.6.5';
/**
* Error severity: message only, continue processing.
*
* @var int
*/
const STOP_MESSAGE = 0;
/**
* Error severity: message, likely ok to continue processing.
*
* @var int
*/
const STOP_CONTINUE = 1;
/**
* Error severity: message, plus full stop, critical error reached.
*
* @var int
*/
const STOP_CRITICAL = 2;
/**
* The SMTP standard CRLF line break.
* If you want to change line break format, change static::$LE, not this.
*/
const CRLF = "\r\n";
/**
* "Folding White Space" a white space string used for line folding.
*/
const FWS = ' ';
/**
* SMTP RFC standard line ending; Carriage Return, Line Feed.
*
* @var string
*/
protected static $LE = self::CRLF;
/**
* The maximum line length supported by mail().
*
* Background: mail() will sometimes corrupt messages
* with headers headers longer than 65 chars, see #818.
*
* @var int
*/
const MAIL_MAX_LINE_LENGTH = 63;
/**
* The maximum line length allowed by RFC 2822 section 2.1.1.
*
* @var int
*/
const MAX_LINE_LENGTH = 998;
/**
* The lower maximum line length allowed by RFC 2822 section 2.1.1.
* This length does NOT include the line break
* 76 means that lines will be 77 or 78 chars depending on whether
* the line break format is LF or CRLF; both are valid.
*
* @var int
*/
const STD_LINE_LENGTH = 76;
/**
* Constructor.
*
* @param bool $exceptions Should we throw external exceptions?
*/
public function __construct($exceptions = null)
{
if (null !== $exceptions) {
$this->exceptions = (bool) $exceptions;
}
//Pick an appropriate debug output format automatically
$this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
}
/**
* Destructor.
*/
public function __destruct()
{
//Close any open SMTP connection nicely
$this->smtpClose();
}
/**
* Call mail() in a safe_mode-aware fashion.
* Also, unless sendmail_path points to sendmail (or something that
* claims to be sendmail), don't pass params (not a perfect fix,
* but it will do).
*
* @param string $to To
* @param string $subject Subject
* @param string $body Message Body
* @param string $header Additional Header(s)
* @param string|null $params Params
*
* @return bool
*/
private function mailPassthru($to, $subject, $body, $header, $params)
{
//Check overloading of mail function to avoid double-encoding
if (ini_get('mbstring.func_overload') & 1) {
$subject = $this->secureHeader($subject);
} else {
$subject = $this->encodeHeader($this->secureHeader($subject));
}
//Calling mail() with null params breaks
$this->edebug('Sending with mail()');
$this->edebug('Sendmail path: ' . ini_get('sendmail_path'));
$this->edebug("Envelope sender: {$this->Sender}");
$this->edebug("To: {$to}");
$this->edebug("Subject: {$subject}");
$this->edebug("Headers: {$header}");
if (!$this->UseSendmailOptions || null === $params) {
$result = @mail($to, $subject, $body, $header);
} else {
$this->edebug("Additional params: {$params}");
$result = @mail($to, $subject, $body, $header, $params);
}
$this->edebug('Result: ' . ($result ? 'true' : 'false'));
return $result;
}
/**
* Output debugging info via a user-defined method.
* Only generates output if debug output is enabled.
*
* @see PHPMailer::$Debugoutput
* @see PHPMailer::$SMTPDebug
*
* @param string $str
*/
protected function edebug($str)
{
if ($this->SMTPDebug <= 0) {
return;
}
//Is this a PSR-3 logger?
if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) {
$this->Debugoutput->debug($str);
return;
}
//Avoid clash with built-in function names
if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) {
call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
return;
}
switch ($this->Debugoutput) {
case 'error_log':
//Don't output, just log
/** @noinspection ForgottenDebugOutputInspection */
error_log($str);
break;
case 'html':
//Cleans up output a bit for a better looking, HTML-safe output
echo htmlentities(
preg_replace('/[\r\n]+/', '', $str),
ENT_QUOTES,
'UTF-8'
), "
\n";
break;
case 'echo':
default:
//Normalize line breaks
$str = preg_replace('/\r\n|\r/m', "\n", $str);
echo gmdate('Y-m-d H:i:s'),
"\t",
//Trim trailing space
trim(
//Indent for readability, except for trailing break
str_replace(
"\n",
"\n \t ",
trim($str)
)
),
"\n";
}
}
/**
* Sets message type to HTML or plain.
*
* @param bool $isHtml True for HTML mode
*/
public function isHTML($isHtml = true)
{
if ($isHtml) {
$this->ContentType = static::CONTENT_TYPE_TEXT_HTML;
} else {
$this->ContentType = static::CONTENT_TYPE_PLAINTEXT;
}
}
/**
* Send messages using SMTP.
*/
public function isSMTP()
{
$this->Mailer = 'smtp';
}
/**
* Send messages using PHP's mail() function.
*/
public function isMail()
{
$this->Mailer = 'mail';
}
/**
* Send messages using $Sendmail.
*/
public function isSendmail()
{
$ini_sendmail_path = ini_get('sendmail_path');
if (false === stripos($ini_sendmail_path, 'sendmail')) {
$this->Sendmail = '/usr/sbin/sendmail';
} else {
$this->Sendmail = $ini_sendmail_path;
}
$this->Mailer = 'sendmail';
}
/**
* Send messages using qmail.
*/
public function isQmail()
{
$ini_sendmail_path = ini_get('sendmail_path');
if (false === stripos($ini_sendmail_path, 'qmail')) {
$this->Sendmail = '/var/qmail/bin/qmail-inject';
} else {
$this->Sendmail = $ini_sendmail_path;
}
$this->Mailer = 'qmail';
}
/**
* Add a "To" address.
*
* @param string $address The email address to send to
* @param string $name
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
public function addAddress($address, $name = '')
{
return $this->addOrEnqueueAnAddress('to', $address, $name);
}
/**
* Add a "CC" address.
*
* @param string $address The email address to send to
* @param string $name
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
public function addCC($address, $name = '')
{
return $this->addOrEnqueueAnAddress('cc', $address, $name);
}
/**
* Add a "BCC" address.
*
* @param string $address The email address to send to
* @param string $name
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
public function addBCC($address, $name = '')
{
return $this->addOrEnqueueAnAddress('bcc', $address, $name);
}
/**
* Add a "Reply-To" address.
*
* @param string $address The email address to reply to
* @param string $name
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
public function addReplyTo($address, $name = '')
{
return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
}
/**
* Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
* can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
* be modified after calling this function), addition of such addresses is delayed until send().
* Addresses that have been added already return false, but do not throw exceptions.
*
* @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
* @param string $address The email address
* @param string $name An optional username associated with the address
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
protected function addOrEnqueueAnAddress($kind, $address, $name)
{
$pos = false;
if ($address !== null) {
$address = trim($address);
$pos = strrpos($address, '@');
}
if (false === $pos) {
//At-sign is missing.
$error_message = sprintf(
'%s (%s): %s',
$this->lang('invalid_address'),
$kind,
$address
);
$this->setError($error_message);
$this->edebug($error_message);
if ($this->exceptions) {
throw new Exception($error_message);
}
return false;
}
if ($name !== null && is_string($name)) {
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
} else {
$name = '';
}
$params = [$kind, $address, $name];
//Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
//Domain is assumed to be whatever is after the last @ symbol in the address
if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) {
if ('Reply-To' !== $kind) {
if (!array_key_exists($address, $this->RecipientsQueue)) {
$this->RecipientsQueue[$address] = $params;
return true;
}
} elseif (!array_key_exists($address, $this->ReplyToQueue)) {
$this->ReplyToQueue[$address] = $params;
return true;
}
return false;
}
//Immediately add standard addresses without IDN.
return call_user_func_array([$this, 'addAnAddress'], $params);
}
/**
* Add an address to one of the recipient arrays or to the ReplyTo array.
* Addresses that have been added already return false, but do not throw exceptions.
*
* @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
* @param string $address The email address to send, resp. to reply to
* @param string $name
*
* @throws Exception
*
* @return bool true on success, false if address already used or invalid in some way
*/
protected function addAnAddress($kind, $address, $name = '')
{
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
$error_message = sprintf(
'%s: %s',
$this->lang('Invalid recipient kind'),
$kind
);
$this->setError($error_message);
$this->edebug($error_message);
if ($this->exceptions) {
throw new Exception($error_message);
}
return false;
}
if (!static::validateAddress($address)) {
$error_message = sprintf(
'%s (%s): %s',
$this->lang('invalid_address'),
$kind,
$address
);
$this->setError($error_message);
$this->edebug($error_message);
if ($this->exceptions) {
throw new Exception($error_message);
}
return false;
}
if ('Reply-To' !== $kind) {
if (!array_key_exists(strtolower($address), $this->all_recipients)) {
$this->{$kind}[] = [$address, $name];
$this->all_recipients[strtolower($address)] = true;
return true;
}
} elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
$this->ReplyTo[strtolower($address)] = [$address, $name];
return true;
}
return false;
}
/**
* Parse and validate a string containing one or more RFC822-style comma-separated email addresses
* of the form "display name