Підсумок
Через помилку в WP Core, надсилання багаточастинних електронних листів (html / текст) з wp_mail () (щоб зменшити ймовірність надходження електронних листів у папки спаму) іронічно призведе до того, що ваш домен буде заблокований Hotmail (та іншими електронними листами Microsoft).
Це складна проблема, яку я маю на меті розкрити докладно, намагаючись допомогти комусь знайти ефективне рішення, яке згодом може бути реалізовано в основі.
Це буде корисним читанням. Давайте почнемо...
Клоп
Найпоширеніша порада уникати надсилання електронних листів у папках із спамом - надсилати повідомлення з кількома частинами.
Багаточастинка (mime) стосується надсилання як HTML, так і TEXT частини електронного повідомлення в один електронний лист. Коли клієнт отримує багаточасткове повідомлення, він приймає версію HTML, якщо він може надати HTML, інакше він представляє звичайну текстову версію.
Це, як доведено, працює. При надсиланні на gmail всі наші електронні листи потрапляли у папки зі спамом, поки ми не змінили повідомлення на багаточастинні, коли вони перейшли до основної скриньки. Чудові речі.
Тепер, надсилаючи багаточастинні повідомлення через 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
може бути рядок.
wp_mail()
функція підключається, чи не визначає вашу заміну як плагін, що використовується (у wp-content / mu-plugins), не для вас (і для всіх інших, не вдається виправити ядро)? У такому випадку не переміщення багаточастинної / граничної перевірки на те, щоб після встановлення$phpmailer->ContentType = $content_type;
(а не про elsing) не працювало?