: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_ALTERNATIVE . ';');
$body .= $this->textLine(' boundary="' . $this->boundary[2] . '"');
$body .= $this->getBoundary(
static::CONTENT_TYPE_PLAINTEXT,
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
$body .= $this->getBoundary(
static::CONTENT_TYPE_TEXT_HTML,
$body .= $this->encodeString($this->Body, $bodyEncoding);
if (!empty($this->Ical)) {
$method = static::ICAL_METHOD_REQUEST;
foreach (static::$IcalMethods as $imethod) {
if (stripos($this->Ical, 'METHOD:' . $imethod) !== false) {
$body .= $this->getBoundary(
static::CONTENT_TYPE_TEXT_CALENDAR . '; method=' . $method,
$body .= $this->encodeString($this->Ical, $this->Encoding);
$body .= $this->endBoundary($this->boundary[2]);
$body .= $this->attachAll('attachment', $this->boundary[1]);
case 'alt_inline_attach':
$body .= $this->textLine('--' . $this->boundary[1]);
$body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_ALTERNATIVE . ';');
$body .= $this->textLine(' boundary="' . $this->boundary[2] . '"');
$body .= $this->getBoundary(
static::CONTENT_TYPE_PLAINTEXT,
$body .= $this->encodeString($this->AltBody, $altBodyEncoding);
$body .= $this->textLine('--' . $this->boundary[2]);
$body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_RELATED . ';');
$body .= $this->textLine(' boundary="' . $this->boundary[3] . '";');
$body .= $this->textLine(' type="' . static::CONTENT_TYPE_TEXT_HTML . '"');
$body .= $this->getBoundary(
static::CONTENT_TYPE_TEXT_HTML,
$body .= $this->encodeString($this->Body, $bodyEncoding);
$body .= $this->attachAll('inline', $this->boundary[3]);
$body .= $this->endBoundary($this->boundary[2]);
$body .= $this->attachAll('attachment', $this->boundary[1]);
//Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
//Reset the `Encoding` property in case we changed it for line length reasons
$this->Encoding = $bodyEncoding;
$body .= $this->encodeString($this->Body, $this->Encoding);
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
} elseif ($this->sign_key_file) {
if (!defined('PKCS7_TEXT')) {
throw new Exception($this->lang('extension_missing') . 'openssl');
$file = tempnam(sys_get_temp_dir(), 'srcsign');
$signed = tempnam(sys_get_temp_dir(), 'mailsign');
file_put_contents($file, $body);
//Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
if (empty($this->sign_extracerts_file)) {
$sign = @openssl_pkcs7_sign(
'file://' . realpath($this->sign_cert_file),
['file://' . realpath($this->sign_key_file), $this->sign_key_pass],
$sign = @openssl_pkcs7_sign(
'file://' . realpath($this->sign_cert_file),
['file://' . realpath($this->sign_key_file), $this->sign_key_pass],
$this->sign_extracerts_file
$body = file_get_contents($signed);
//The message returned by openssl contains both headers and body, so need to split them up
$parts = explode("\n\n", $body, 2);
$this->MIMEHeader .= $parts[0] . static::$LE . static::$LE;
throw new Exception($this->lang('signing') . openssl_error_string());
} catch (Exception $exc) {
* Get the boundaries that this message will use
public function getBoundaries()
if (empty($this->boundary)) {
* Return the start of a message boundary.
* @param string $boundary
* @param string $contentType
* @param string $encoding
protected function getBoundary($boundary, $charSet, $contentType, $encoding)
$charSet = $this->CharSet;
if ('' === $contentType) {
$contentType = $this->ContentType;
$encoding = $this->Encoding;
$result .= $this->textLine('--' . $boundary);
$result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
//RFC1341 part 5 says 7bit is assumed if not specified
if (static::ENCODING_7BIT !== $encoding) {
$result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
* Return the end of a message boundary.
* @param string $boundary
protected function endBoundary($boundary)
return static::$LE . '--' . $boundary . '--' . static::$LE;
* PHPMailer only supports some preset message types, not arbitrary MIME structures.
protected function setMessageType()
if ($this->alternativeExists()) {
if ($this->inlineImageExists()) {
if ($this->attachmentExists()) {
$this->message_type = implode('_', $type);
if ('' === $this->message_type) {
//The 'plain' message_type refers to the message having a single body element, not that it is plain-text
$this->message_type = 'plain';
* @param string|int $value
public function headerLine($name, $value)
return $name . ': ' . $value . static::$LE;
* Return a formatted mail line.
public function textLine($value)
return $value . static::$LE;
* Add an attachment from a path on the filesystem.
* Never use a user-supplied path to a file!
* Returns false if the file could not be found or read.
* Explicitly *does not* support passing URLs; PHPMailer is not an HTTP client.
* If you need to do that, fetch the resource yourself and pass it in via a local file or string.
* @param string $path Path to the attachment
* @param string $name Overrides the attachment name
* @param string $encoding File encoding (see $Encoding)
* @param string $type MIME type, e.g. `image/jpeg`; determined automatically from $path if not specified
* @param string $disposition Disposition to use
public function addAttachment(
$encoding = self::ENCODING_BASE64,
$disposition = 'attachment'
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
//If a MIME type is not specified, try to work it out from the file name
$type = static::filenameToType($path);
$filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME);
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
5 => false, //isStringAttachment
} catch (Exception $exc) {
$this->setError($exc->getMessage());
$this->edebug($exc->getMessage());
* Return the array of attachments.
public function getAttachments()
return $this->attachment;
* Attach all file, string, and binary attachments to the message.
* Returns an empty string on failure.
* @param string $disposition_type
* @param string $boundary
protected function attachAll($disposition_type, $boundary)
foreach ($this->attachment as $attachment) {
//Check if it is a valid disposition_filter
if ($attachment[6] === $disposition_type) {
//Check for string attachment
$bString = $attachment[5];
$string = $attachment[0];
$inclhash = hash('sha256', serialize($attachment));
if (in_array($inclhash, $incl, true)) {
$encoding = $attachment[3];
$disposition = $attachment[6];
if ('inline' === $disposition && array_key_exists($cid, $cidUniq)) {
$mime[] = sprintf('--%s%s', $boundary, static::$LE);
//Only include a filename property if we have one
'Content-Type: %s; name=%s%s',
static::quotedString($this->encodeHeader($this->secureHeader($name))),
//RFC1341 part 5 says 7bit is assumed if not specified
if (static::ENCODING_7BIT !== $encoding) {
$mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE);
//Only set Content-IDs on inline attachments
if ((string) $cid !== '' && $disposition === 'inline') {
$mime[] = 'Content-ID: <' . $this->encodeHeader($this->secureHeader($cid)) . '>' . static::$LE;
//Allow for bypassing the Content-Disposition header
if (!empty($disposition)) {
$encoded_name = $this->encodeHeader($this->secureHeader($name));
if (!empty($encoded_name)) {
'Content-Disposition: %s; filename=%s%s',
static::quotedString($encoded_name),
static::$LE . static::$LE
'Content-Disposition: %s%s',
static::$LE . static::$LE
//Encode as string attachment
$mime[] = $this->encodeString($string, $encoding);
$mime[] = $this->encodeFile($path, $encoding);
$mime[] = sprintf('--%s--%s', $boundary, static::$LE);
return implode('', $mime);
* Encode a file attachment in requested format.
* Returns an empty string on failure.
* @param string $path The full path to the file
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
protected function encodeFile($path, $encoding = self::ENCODING_BASE64)
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
$file_buffer = file_get_contents($path);
if (false === $file_buffer) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
$file_buffer = $this->encodeString($file_buffer, $encoding);
} catch (Exception $exc) {
$this->setError($exc->getMessage());
$this->edebug($exc->getMessage());
* Encode a string in requested format.
* Returns an empty string on failure.
* @param string $str The text to encode
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
public function encodeString($str, $encoding = self::ENCODING_BASE64)
switch (strtolower($encoding)) {
case static::ENCODING_BASE64:
case static::ENCODING_7BIT:
case static::ENCODING_8BIT:
$encoded = static::normalizeBreaks($str);
//Make sure it ends with a line break
if (substr($encoded, -(strlen(static::$LE))) !== static::$LE) {
case static::ENCODING_BINARY:
case static::ENCODING_QUOTED_PRINTABLE:
$encoded = $this->encodeQP($str);