Intereting Posts
Передача таксономии идентификатора таксономии нажата на одной странице на другую страницу Является ли номер сообщения всегда инкрементным n + Сортировка запроса по пользовательской дате поля Различные таксономии.php для разных пользовательских типов сообщений Обновить размер прикрепленного изображения после импорта Ошибка в WP_update_post Закажите meta_key с помощью двух meta_queries jQuery из родительской темы, загружаемой многими другими скриптами в один файл min.js Как проверить, загружена ли таблица стилей? Как обновлять фид только 2-3 раза в неделю (для электронной почты Feedburner)? WP Query – дублированные сообщения, включая теги в результатах поиска Лучшие практики сервера WordPress и сервера разработки ajax jquery update custom field meta value front end Ошибка 404 при сохранении или просмотре одной конкретной страницы Скрыть защищенные паролем сообщения

Отправка писем multipart (text / html) через wp_mail () скорее всего приведет к запрету вашего домена

Резюме

Из-за ошибки в WP Core отправка почтовых сообщений (html / text) с помощью wp_mail () (для уменьшения вероятности появления электронных писем в папках со спамом) по иронии судьбы приведет к блокировке вашего домена Hotmail (и другими электронными письмами Microsoft).

Это сложная проблема, с которой я попытаюсь разобраться в деталях, пытаясь помочь кому-то найти работоспособное решение, которое в конечном итоге может быть реализовано в ядре.

Это будет полезное чтение. Давай начнем…

Баг

Наиболее распространенный совет, чтобы избежать попадания ваших электронных писем в папку спама, является отправка многостраничных сообщений.

Multi-part (mime) относится к отправке как HTML, так и TEXT части сообщения электронной почты в одном электронном письме. Когда клиент получает многостраничное сообщение, он принимает версию HTML, если он может отображать HTML, иначе он представляет собой текстовую версию.

Это доказало свою эффективность. При отправке в gmail все наши письма попадали в папки спама, пока мы не изменили сообщения на multipart, когда они попали в основной почтовый ящик. Качественный товар.

Теперь, когда вы отправляете многостраничные сообщения через wp_mail (), он дважды выводит тип содержимого (multipart / *), один раз с границей (если установлен на заказ) и один раз без него. Это приводит к тому, что сообщение электронной почты отображается как необработанное сообщение, а не на нескольких электронных сообщениях, включая все Microsoft (Hotmail, Outlook и т. Д.).

Microsoft будет помечать это сообщение как нежелательное, и несколько сообщений, которые будут отправлены, будут помечены вручную получателем. К сожалению , адреса электронной почты Microsoft широко используются. Его используют 40%.

Это подтверждается Microsoft через обмен электронной почтой, который мы недавно получили.

Пометка сообщений будет результатом полного блокирования домена. Это означает, что сообщение не будет отправлено в папку спама, они даже не будут доставлены получателю.

До сих пор наш основной домен заблокирован 3 раза.

Поскольку это ошибка в ядре WP, каждый домен, отправляющий многостраничные сообщения, блокируется. Проблема в том, что большинство веб-мастеров не знают, почему. Я подтвердил это, проводя исследование и наблюдая за тем, как другие пользователи обсуждают это на форумах и т. Д. Это требует вникания в исходный код и хорошего знания того, как работают эти типы сообщений электронной почты, которые мы собираемся продолжить …

Давайте разложим его на код

Создайте учетную запись hotmail / outlook. Затем запустите следующий код:

// Set $to to an hotmail.com or outlook.com email $to = "YourEmail@hotmail.com"; $subject = 'wp_mail testing multipart'; $message = '------=_Part_18243133_1346573420.1408991447668 Content-Type: text/plain; charset=UTF-8 Hello world! This is plain text... ------=_Part_18243133_1346573420.1408991447668 Content-Type: text/html; charset=UTF-8 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p>Hello World! This is HTML...</p> </body> </html> ------=_Part_18243133_1346573420.1408991447668--'; $headers = "MIME-Version: 1.0\r\n"; $headers .= "From: Foo <foo@bar.com>\r\n"; $headers .= 'Content-Type: multipart/alternative;boundary="----=_Part_18243133_1346573420.1408991447668"'; // send email wp_mail( $to, $subject, $message, $headers ); 

И если вы хотите изменить тип контента по умолчанию , используйте:

 add_filter( 'wp_mail_content_type', 'set_content_type' ); function set_content_type( $content_type ) { return 'multipart/alternative'; } 

Это отправит многостраничное сообщение.

Поэтому, если вы проверите полный исходный текст сообщения, вы заметите, что тип контента добавляется дважды, один раз без границы:

 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="====f230673f9d7c359a81ffebccb88e5d61==" MIME-Version: 1.0 Content-Type: multipart/alternative; charset= 

Это проблема.

Источником проблемы является pluggable.php – если мы посмотрим где-то здесь:

 // Set Content-Type and charset // If we don't have a content-type from the input headers if ( !isset( $content_type ) ) $content_type = 'text/plain'; /** * Filter the wp_mail() content type. * * @since 2.3.0 * * @param string $content_type Default wp_mail() content type. */ $content_type = apply_filters( 'wp_mail_content_type', $content_type ); $phpmailer->ContentType = $content_type; // Set whether it's plaintext, depending on $content_type if ( 'text/html' == $content_type ) $phpmailer->IsHTML( true ); // If we don't have a charset from the input headers if ( !isset( $charset ) ) $charset = get_bloginfo( 'charset' ); // Set the content-type and charset /** * Filter the default wp_mail() charset. * * @since 2.3.0 * * @param string $charset Default email charset. */ $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset ); // Set custom headers if ( !empty( $headers ) ) { foreach( (array) $headers as $name => $content ) { $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); } if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) ); } if ( !empty( $attachments ) ) { foreach ( $attachments as $attachment ) { try { $phpmailer->AddAttachment($attachment); } catch ( phpmailerException $e ) { continue; } } } 

Потенциальные решения

Так что вам интересно, почему вы не сообщили об этом в trac ? У меня уже есть . К моему большому удивлению, 5 лет назад был создан другой билет, в котором была изложена одна и та же проблема.

Посмотрим правде в глаза, прошло уже полтора десятилетия. В интернет-годы это больше похоже на 30. Проблема явно оставлена ​​и в принципе никогда не будет исправлена ​​(… если только мы ее не разрешим здесь).

Я нашел замечательную тему, предлагающую решение, но пока его решение работает, оно разбивает электронные письма, у которых нет настраиваемых $headers .

Вот тут мы каждый раз рушимся. Либо многостраничная версия работает нормально, либо нормальные сообщения об отключении $headers , или стихи стихов.

Решение, с которым мы столкнулись, было:

 if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) { $phpmailer->ContentType = $content_type . "; boundary=" . $boundary; } else { $content_type = apply_filters( 'wp_mail_content_type', $content_type ); $phpmailer->ContentType = $content_type; // Set whether it's plaintext, depending on $content_type if ( 'text/html' == $content_type ) $phpmailer->IsHTML( true ); // If we don't have a charset from the input headers if ( !isset( $charset ) ) $charset = get_bloginfo( 'charset' ); } // Set the content-type and charset /** * Filter the default wp_mail() charset. * * @since 2.3.0 * * @param string $charset Default email charset. */ $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset ); // Set custom headers if ( !empty( $headers ) ) { foreach( (array) $headers as $name => $content ) { $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); } } 

Да, я знаю, редактирование основных файлов табу, сидеть сложа руки … это было отчаянное исправление и плохая попытка предоставить исправление для ядра.

Проблема с нашим исправлением заключается в том, что по умолчанию электронные письма, такие как новые регистрации, комментарий, сброс пароля и т. Д., Будут доставлены в виде пустых сообщений. Таким образом, у нас есть рабочий скрипт wp_mail (), который будет отправлять многостраничные сообщения, но ничего другого.

Что делать

Целью здесь является найти способ отправки как обычного (обычного текста), так и многостраничных сообщений с использованием функции основного wp_mail () (а не пользовательской функции sendmail).

При попытке решить эту проблему основная проблема, с которой вы столкнетесь, – это время, которое вы потратите на отправку фиктивных сообщений, проверку их получения и, в основном, открытие коробки аспирина и проклятие в Microsoft, потому что вы привыкли к их IE проблемы, в то время как гремлин здесь, к сожалению, WordPress.

Обновить

Решение, отправленное @bonger, позволяет $message быть массивом, содержащим чередование с типом контента. Я подтвердил, что он работает во всех сценариях.

Мы разрешим этот вопрос оставаться открытым до тех пор, пока не удастся победить, чтобы повысить осведомленность о проблеме, возможно, до уровня, где он будет исправлен в ядре. Не стесняйтесь публиковать альтернативное решение, где $message может быть строкой.

Solutions Collecting From Web of "Отправка писем multipart (text / html) через wp_mail () скорее всего приведет к запрету вашего домена"

Следующая версия wp_mail() с патчем, применяемым в @ rmccue / @ MattyRob в билете https://core.trac.wordpress.org/ticket/15448 , обновленном для 4.2.2, что позволяет $message быть массив, содержащий чередующиеся подписи типа контента:

 /** * Send mail, similar to PHP's mail * * A true return value does not automatically mean that the user received the * email successfully. It just only means that the method used was able to * process the request without any errors. * * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from * creating a from address like 'Name <email@address.com>' when both are set. If * just 'wp_mail_from' is set, then just the email address will be used with no * name. * * The default content type is 'text/plain' which does not allow using HTML. * However, you can set the content type of the email by using the * 'wp_mail_content_type' filter. * * If $message is an array, the key of each is used to add as an attachment * with the value used as the body. The 'text/plain' element is used as the * text version of the body, with the 'text/html' element used as the HTML * version of the body. All other types are added as attachments. * * The default charset is based on the charset used on the blog. The charset can * be set using the 'wp_mail_charset' filter. * * @since 1.2.1 * * @uses PHPMailer * * @param string|array $to Array or comma-separated list of email addresses to send message. * @param string $subject Email subject * @param string|array $message Message contents * @param string|array $headers Optional. Additional headers. * @param string|array $attachments Optional. Files to attach. * @return bool Whether the email contents were sent successfully. */ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) { // Compact the input, apply the filters, and extract them back out /** * Filter the wp_mail() arguments. * * @since 2.2.0 * * @param array $args A compacted array of wp_mail() arguments, including the "to" email, * subject, message, headers, and attachments values. */ $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ); if ( isset( $atts['to'] ) ) { $to = $atts['to']; } if ( isset( $atts['subject'] ) ) { $subject = $atts['subject']; } if ( isset( $atts['message'] ) ) { $message = $atts['message']; } if ( isset( $atts['headers'] ) ) { $headers = $atts['headers']; } if ( isset( $atts['attachments'] ) ) { $attachments = $atts['attachments']; } if ( ! is_array( $attachments ) ) { $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) ); } global $phpmailer; // (Re)create it, if it's gone missing if ( ! ( $phpmailer instanceof PHPMailer ) ) { require_once ABSPATH . WPINC . '/class-phpmailer.php'; require_once ABSPATH . WPINC . '/class-smtp.php'; $phpmailer = new PHPMailer( true ); } // Headers if ( empty( $headers ) ) { $headers = array(); } else { if ( !is_array( $headers ) ) { // Explode the headers out, so this function can take both // string headers and an array of headers. $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) ); } else { $tempheaders = $headers; } $headers = array(); $cc = array(); $bcc = array(); // If it's actually got contents if ( !empty( $tempheaders ) ) { // Iterate through the raw headers foreach ( (array) $tempheaders as $header ) { if ( strpos($header, ':') === false ) { if ( false !== stripos( $header, 'boundary=' ) ) { $parts = preg_split('/boundary=/i', trim( $header ) ); $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) ); } continue; } // Explode them out list( $name, $content ) = explode( ':', trim( $header ), 2 ); // Cleanup crew $name = trim( $name ); $content = trim( $content ); switch ( strtolower( $name ) ) { // Mainly for legacy -- process a From: header if it's there case 'from': $bracket_pos = strpos( $content, '<' ); if ( $bracket_pos !== false ) { // Text before the bracketed email is the "From" name. if ( $bracket_pos > 0 ) { $from_name = substr( $content, 0, $bracket_pos - 1 ); $from_name = str_replace( '"', '', $from_name ); $from_name = trim( $from_name ); } $from_email = substr( $content, $bracket_pos + 1 ); $from_email = str_replace( '>', '', $from_email ); $from_email = trim( $from_email ); // Avoid setting an empty $from_email. } elseif ( '' !== trim( $content ) ) { $from_email = trim( $content ); } break; case 'content-type': if ( is_array($message) ) { // Multipart email, ignore the content-type header break; } if ( strpos( $content, ';' ) !== false ) { list( $type, $charset_content ) = explode( ';', $content ); $content_type = trim( $type ); if ( false !== stripos( $charset_content, 'charset=' ) ) { $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) ); } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) { $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) ); $charset = ''; } // Avoid setting an empty $content_type. } elseif ( '' !== trim( $content ) ) { $content_type = trim( $content ); } break; case 'cc': $cc = array_merge( (array) $cc, explode( ',', $content ) ); break; case 'bcc': $bcc = array_merge( (array) $bcc, explode( ',', $content ) ); break; default: // Add it to our grand headers array $headers[trim( $name )] = trim( $content ); break; } } } } // Empty out the values that may be set $phpmailer->ClearAllRecipients(); $phpmailer->ClearAttachments(); $phpmailer->ClearCustomHeaders(); $phpmailer->ClearReplyTos(); $phpmailer->Body= ''; $phpmailer->AltBody= ''; // From email and name // If we don't have a name from the input headers if ( !isset( $from_name ) ) $from_name = 'WordPress'; /* If we don't have an email from the input headers default to wordpress@$sitename * Some hosts will block outgoing mail from this address if it doesn't exist but * there's no easy alternative. Defaulting to admin_email might appear to be another * option but some hosts may refuse to relay mail from an unknown domain. See * https://core.trac.wordpress.org/ticket/5007. */ if ( !isset( $from_email ) ) { // Get the site domain and get rid of www. $sitename = strtolower( $_SERVER['SERVER_NAME'] ); if ( substr( $sitename, 0, 4 ) == 'www.' ) { $sitename = substr( $sitename, 4 ); } $from_email = 'wordpress@' . $sitename; } /** * Filter the email address to send from. * * @since 2.2.0 * * @param string $from_email Email address to send from. */ $phpmailer->From = apply_filters( 'wp_mail_from', $from_email ); /** * Filter the name to associate with the "from" email address. * * @since 2.3.0 * * @param string $from_name Name associated with the "from" email address. */ $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name ); // Set destination addresses if ( !is_array( $to ) ) $to = explode( ',', $to ); foreach ( (array) $to as $recipient ) { try { // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" $recipient_name = ''; if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { if ( count( $matches ) == 3 ) { $recipient_name = $matches[1]; $recipient = $matches[2]; } } $phpmailer->AddAddress( $recipient, $recipient_name); } catch ( phpmailerException $e ) { continue; } } // If we don't have a charset from the input headers if ( !isset( $charset ) ) $charset = get_bloginfo( 'charset' ); // Set the content-type and charset /** * Filter the default wp_mail() charset. * * @since 2.3.0 * * @param string $charset Default email charset. */ $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset ); // Set mail's subject and body $phpmailer->Subject = $subject; if ( is_string($message) ) { $phpmailer->Body = $message; // Set Content-Type and charset // If we don't have a content-type from the input headers if ( !isset( $content_type ) ) $content_type = 'text/plain'; /** * Filter the wp_mail() content type. * * @since 2.3.0 * * @param string $content_type Default wp_mail() content type. */ $content_type = apply_filters( 'wp_mail_content_type', $content_type ); $phpmailer->ContentType = $content_type; // Set whether it's plaintext, depending on $content_type if ( 'text/html' == $content_type ) $phpmailer->IsHTML( true ); // For backwards compatibility, new multipart emails should use // the array style $message. This never really worked well anyway if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) ); } elseif ( is_array($message) ) { foreach ($message as $type => $bodies) { foreach ((array) $bodies as $body) { if ($type === 'text/html') { $phpmailer->Body = $body; } elseif ($type === 'text/plain') { $phpmailer->AltBody = $body; } else { $phpmailer->AddAttachment($body, '', 'base64', $type); } } } } // Add any CC and BCC recipients if ( !empty( $cc ) ) { foreach ( (array) $cc as $recipient ) { try { // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" $recipient_name = ''; if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { if ( count( $matches ) == 3 ) { $recipient_name = $matches[1]; $recipient = $matches[2]; } } $phpmailer->AddCc( $recipient, $recipient_name ); } catch ( phpmailerException $e ) { continue; } } } if ( !empty( $bcc ) ) { foreach ( (array) $bcc as $recipient) { try { // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" $recipient_name = ''; if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) { if ( count( $matches ) == 3 ) { $recipient_name = $matches[1]; $recipient = $matches[2]; } } $phpmailer->AddBcc( $recipient, $recipient_name ); } catch ( phpmailerException $e ) { continue; } } } // Set to use PHP's mail() $phpmailer->IsMail(); // Set custom headers if ( !empty( $headers ) ) { foreach ( (array) $headers as $name => $content ) { $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); } } if ( !empty( $attachments ) ) { foreach ( $attachments as $attachment ) { try { $phpmailer->AddAttachment($attachment); } catch ( phpmailerException $e ) { continue; } } } /** * Fires after PHPMailer is initialized. * * @since 2.2.0 * * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference. */ do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); // Send! try { return $phpmailer->Send(); } catch ( phpmailerException $e ) { return false; } } 

Поэтому, если вы поместите это в свой файл «wp-content / mu-plugins / functions.php», то он переопределит версию WP. Он имеет приятное использование без каких-либо конфликтов с заголовками, например:

 // Set $to to an hotmail.com or outlook.com email $to = "YourEmail@hotmail.com"; $subject = 'wp_mail testing multipart'; $message['text/plain'] = 'Hello world! This is plain text...'; $message['text/html'] = '<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p>Hello World! This is HTML...</p> </body> </html>'; add_filter( 'wp_mail_from', $from_func = function ( $from_email ) { return 'foo@bar.com'; } ); add_filter( 'wp_mail_from_name', $from_name_func = function ( $from_name ) { return 'Foo'; } ); // send email wp_mail( $to, $subject, $message ); remove_filter( 'wp_mail_from', $from_func ); remove_filter( 'wp_mail_from_name', $from_name_func ); 

Обратите внимание, что я не тестировал это с помощью фактических писем …

Это вообще не ошибка WordPress, это phpmailer не позволяющий настраивать заголовки … если вы посмотрите на class-phpmailer.php :

 public function getMailMIME() { $result = ''; $ismultipart = true; switch ($this->message_type) { case 'inline': $result .= $this->headerLine('Content-Type', 'multipart/related;'); $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); break; case 'attach': case 'inline_attach': case 'alt_attach': case 'alt_inline_attach': $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); break; case 'alt': case 'alt_inline': $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); break; default: // Catches case 'plain': and case '': $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); $ismultipart = false; break; } 

Вы можете видеть, что причиной нарушения является то, что выводит дополнительную строку заголовка с кодировкой и без границ. Установка типа содержимого по фильтру не решает этого сама по себе только потому, что здесь используется случай alt здесь по AltBody message_type , проверяя, что AltBody не пуст, а не тип содержимого.

 protected function setMessageType() { $type = array(); if ($this->alternativeExists()) { $type[] = 'alt'; } if ($this->inlineImageExists()) { $type[] = 'inline'; } if ($this->attachmentExists()) { $type[] = 'attach'; } $this->message_type = implode('_', $type); if ($this->message_type == '') { $this->message_type = 'plain'; } } public function alternativeExists() { return !empty($this->AltBody); } 

В конце концов, это означает, что как только вы присоедините файл или встроенное изображение или установите AltBody , ошибка обхода должна быть обойдена. Это также означает, что нет необходимости явно AltBody тип содержимого, потому что, как только есть AltBody он устанавливается для multipart/alternative помощью phpmailer .

Итак, простой ответ:

 add_action('phpmailer_init','wp_mail_set_text_body'); function wp_mail_set_text_body($phpmailer) { if (empty($phpmailer->AltBody)) {$phpmailer->AltBody = strip_tags($phpmailer->Body);} } 

Тогда вам не нужно явно устанавливать заголовки, вы можете просто сделать:

  $message ='<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p>Hello World! This is HTML...</p> </body> </html>'; wp_mail($to,$subject,$message); 

К сожалению, многие функции и свойства в классе phpmailer защищены, если не для этого, допустимой альтернативой было бы просто проверить и переопределить свойство MIMEHeaders помощью phpmailer_init до отправки.

Я только что выпустил плагин, чтобы пользователи могли использовать html-шаблоны в WordPress и Im, играя прямо сейчас в dev-версии, чтобы добавить простой резерв текста. Я сделал следующее, и в моих тестах я вижу только одну добавленную границу, и письма отправляются в Hotmail.

 add_action( 'phpmailer_init', array($this->mailer, 'send_email' ) ); /** * Modify php mailer body with final email * * @since 1.0.0 * @param object $phpmailer */ function send_email( $phpmailer ) { $message = $this->add_template( apply_filters( 'mailtpl/email_content', $phpmailer->Body ) ); $phpmailer->AltBody = $this->replace_placeholders( strip_tags($phpmailer->Body) ); $phpmailer->Body = $this->replace_placeholders( $message ); } 

Поэтому в основном то, что я делаю здесь, это изменить объект phpmailer, загрузить сообщение внутри шаблона html и установить его в свойство Body. Также я взял исходное сообщение и установил свойство AltBody.

Моим простым решением является использование html2text https://github.com/soundasleep/html2text таким образом:

 add_action( 'phpmailer_init', 'phpmailer_init' ); //http://wordpress.stackexchange.com/a/191974 //http://stackoverflow.com/a/2564472 function phpmailer_init( $phpmailer ) { if( $phpmailer->ContentType == 'text/html' ) { $phpmailer->AltBody = Html2Text\Html2Text::convert( $phpmailer->Body ); } } 

Здесь https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 тоже суть.

это не может быть точным ответом на исходный пост здесь, но это альтернатива некоторым из предложенных здесь решений относительно установки alt body

по сути, мне нужно (захотелось) установить отдельный altbody (т.е. открытый текст) дополнительно к html-части вместо того, чтобы полагаться на некоторые преобразования / striptags и еще что-то. поэтому я придумал это, которое, кажется, работает просто отлично

 /* setting the message parts for wp_mail()*/ $markup = array(); $markup['html'] = '<html>some html</html>'; $markup['plaintext'] = 'some plaintext'; /* message we are sending */ $message = maybe_serialize($markup); /* setting alt body distinctly */ add_action('phpmailer_init', array($this, 'set_alt_mail_body')); function set_alt_mail_body($phpmailer){ if( $phpmailer->ContentType == 'text/html' ) { $body_parts = maybe_unserialize($phpmailer->Body); if(!empty($body_parts['html'])){ $phpmailer->MsgHTML($body_parts['html']); } if(!empty($body_parts['plaintext'])){ $phpmailer->AltBody = $body_parts['plaintext']; } } }