Podsumowanie
Z powodu błędu w WP Core wysyłanie wieloczęściowych wiadomości e-mail (html / text) za pomocą wp_mail () (w celu zmniejszenia prawdopodobieństwa, że wiadomości e-mail znajdą się w folderach ze spamem) spowoduje ironiczne zablokowanie domeny przez Hotmail (i inne wiadomości e-mail Microsoft).
Jest to złożony problem, który postaram się szczegółowo wyjaśnić, próbując pomóc komuś znaleźć praktyczne rozwiązanie, które ostatecznie może zostać wdrożone w jądrze.
To będzie satysfakcjonująca lektura. Zaczynajmy...
Błąd
Najczęstszą wskazówką, aby uniknąć sytuacji, w której wiadomości e-mail biuletynu znajdą się w folderach ze spamem, jest wysyłanie wiadomości wieloczęściowych.
Wieloczęściowy (mime) odnosi się do wysyłania zarówno części HTML, jak i TEXT wiadomości e-mail w jednym e-mailu. Gdy klient otrzymuje wiadomość wieloczęściową, akceptuje wersję HTML, jeśli może renderować HTML, w przeciwnym razie wyświetla wersję zwykłego tekstu.
Udowodniono, że to działa. Podczas wysyłania do Gmaila wszystkie nasze e-maile trafiały do folderów spamu, dopóki nie zmieniliśmy wiadomości na wieloczęściowe, gdy dotarły do głównej skrzynki odbiorczej. Świetna sprawa.
Teraz, wysyłając wiadomości wieloczęściowe za pośrednictwem wp_mail (), wysyła Typ treści (wieloczęściowy / *) dwa razy, raz z granicą (jeśli jest to ustawione niestandardowo) i raz bez. To zachowanie powoduje, że wiadomość e-mail jest wyświetlana jako nieprzetworzona wiadomość, a nie wieloczęściowa w niektórych wiadomościach e-mail, w tym we wszystkich Microsoft (Hotmail, Outlook itp.)
Microsoft oznaczy tę wiadomość jako śmieci, a kilka wiadomości, które przejdą, zostanie oflagowane ręcznie przez odbiorcę. Niestety adresy e-mail Microsoft są powszechnie używane. Korzysta z niego 40% naszych subskrybentów.
Potwierdza to Microsoft za pośrednictwem niedawno przeprowadzonej wymiany wiadomości e-mail.
Oznaczenie wiadomości spowoduje całkowite zablokowanie domeny . Oznacza to, że wiadomość nie zostanie wysłana do folderu ze spamem, a nawet nie zostanie dostarczona do odbiorcy.
Do tej pory nasza główna domena była blokowana 3 razy.
Ponieważ jest to błąd w rdzeniu WP, każda domena, która wysyła wiadomości wieloczęściowe, jest blokowana. Problem polega na tym, że większość webmasterów nie wie dlaczego. Potwierdziłem to, przeprowadzając moje badania i widząc, jak inni użytkownicy dyskutują o tym na forach itp. Wymaga to zagłębienia się w surowy kod i dobrej wiedzy o tym, jak działają tego rodzaju wiadomości e-mail, które przechodzimy dalej ...
Podzielmy to na kod
Utwórz konto Hotmail / Outlook. Następnie uruchom następujący kod:
// 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 );
A jeśli chcesz zmienić domyślny typ zawartości , użyj:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Spowoduje to wysłanie wiadomości wieloczęściowej.
Jeśli więc sprawdzisz pełne nieprzetworzone źródło wiadomości, zauważysz, że typ zawartości jest dodawany dwukrotnie, raz bez granic:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
To jest problem.
Źródłem problemu jest pluggable.php
- jeśli spojrzymy gdzieś tutaj:
// 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;
}
}
}
Potencjalne rozwiązania
Zastanawiasz się więc, dlaczego nie zgłosiłeś tego w trac ? I już . Ku mojemu wielkiemu zdziwieniu, 5 lat temu powstał inny bilet opisujący ten sam problem.
Spójrzmy prawdzie w oczy, minęło pół dekady. W latach internetowych jest to więcej niż 30. Problem wyraźnie został porzucony i zasadniczo nigdy nie zostanie rozwiązany (... chyba że rozwiążemy go tutaj).
Znalazłem tutaj świetny wątek oferujący rozwiązanie, ale chociaż jego rozwiązanie działa, łamie wiadomości e-mail, które nie mają niestandardowego $headers
zestawu.
Tam właśnie za każdym razem padamy. Albo wersja wieloczęściowa działa dobrze, a normalne nieuzbrojone $headers
wiadomości nie działają, lub odwrotnie.
Rozwiązaniem, które wymyśliliśmy było:
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 ) );
}
}
Tak, wiem, edytowanie podstawowych plików to tabu, usiądźcie ... to była desperacka poprawka i kiepska próba dostarczenia poprawki dla rdzenia.
Problem z naszą poprawką polega na tym, że domyślne wiadomości e-mail, takie jak nowe rejestracje, komentarze, resetowanie hasła itp. Będą dostarczane jako puste wiadomości. Mamy więc działający skrypt wp_mail (), który będzie wysyłać wiadomości wieloczęściowe, ale nic więcej.
Co robić
Celem jest znalezienie sposobu wysyłania zarówno zwykłych (zwykły tekst), jak i wieloczęściowych wiadomości za pomocą podstawowej funkcji wp_mail () (nie jest to niestandardowa funkcja sendmail).
Podczas próby rozwiązania tego, głównym problemem, jaki napotkasz, jest ilość czasu, którą poświęcisz na wysyłanie fałszywych wiadomości, sprawdzanie, czy zostały odebrane, i po prostu otwieranie pudełka z aspiryną i przeklinanie w Microsoft, ponieważ jesteś przyzwyczajony do ich Problemy z IE, podczas gdy gremlin tutaj jest niestety WordPress.
Aktualizacja
Rozwiązanie opublikowane przez @bonger pozwala $message
być tablicą zawierającą zamienniki z kluczem zawartości. Potwierdziłem, że działa we wszystkich scenariuszach.
Pozwolimy, aby pytanie pozostało otwarte, dopóki nie skończy się nagroda, aby podnieść świadomość problemu, być może do poziomu, w którym zostanie on naprawiony w rdzeniu. Zapraszam do opublikowania alternatywnego rozwiązania, w którym $message
może być ciąg.
wp_mail()
funkcja jest wtykowa, to nie definiowanie zamiennika jako wtyczki, której należy używać (w treściach wt-wp / wtyczek mu), nie jest dobrym rozwiązaniem dla ciebie (i dla wszystkich innych, nie udaje się naprawić rdzenia)? W którym przypadku nie$phpmailer->ContentType = $content_type;
działałoby przeniesienie kontroli wieloczęściowej / granicznej po ustawieniu (zamiast elsowania)?