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 = "[email protected]";
$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 <[email protected]>\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)?wp_mail
można go podłączyć . Skopiuj oryginalną funkcję do wtyczki, edytuj ją tak, jak potrzebujesz i aktywuj wtyczkę. WordPress użyje edytowanej funkcji zamiast oryginalnej, bez potrzeby edycji rdzenia.Odpowiedzi:
Następująca wersja
wp_mail()
jest z poprawką @ rmccue / @ MattyRob w bilecie https://core.trac.wordpress.org/ticket/15448 , odświeżona do 4.2.2, która pozwala$message
być tablicą zawierającą typ zawartości kluczowane alternatywy:Więc jeśli umieścisz to w swoim pliku np. „Wp-content / mu-plugins / functions.php”, to zastąpi wersję WP. Ma ładne zastosowanie bez żadnych bałaganu przy nagłówkach, np .:
Pamiętaj, że nie testowałem tego z rzeczywistymi wiadomościami e-mail ...
źródło
To wcale nie jest błąd WordPressa,
phpmailer
nie pozwala na niestandardowe nagłówki ... jeśli spojrzysz naclass-phpmailer.php
:Możesz zobaczyć, że obrażająca domyślna wielkość jest tym, co wypisuje dodatkową linię nagłówka z charset i bez granicy. Ustawienie typu zawartości według filtru nie rozwiązuje tego samodzielnie, tylko dlatego, że
alt
przypadek jest ustawionymessage_type
przez sprawdzenie, żeAltBody
nie jest pusty, a nie typ zawartości.Ostatecznie oznacza to, jak tylko załączysz plik lub obraz wbudowany, lub ustawisz
AltBody
, winny błąd powinien zostać ominięty. Oznacza to również, że nie ma potrzeby jawnego ustawiania typu zawartości, ponieważ tak szybko, jak toAltBody
możliwe, jest to ustawianemultipart/alternative
przezphpmailer
.Prosta odpowiedź brzmi:
Następnie nie musisz jawnie ustawiać nagłówków, możesz po prostu zrobić:
Na nieszczęście wiele funkcji i właściwości w
phpmailer
klasie jest chronionych, gdyby nie to, poprawną alternatywą byłoby po prostu sprawdzenie i przesłonięcieMIMEHeaders
właściwości za pomocąphpmailer_init
haka przed wysłaniem.źródło
Właśnie wydałem wtyczkę, która pozwala użytkownikom korzystać z szablonów HTML na WordPress i Im teraz odtwarzam wersję dev, aby dodać prosty tekst zastępczy. Wykonałem następujące czynności i podczas testów widzę tylko jedną dodaną granicę, a wiadomości e-mail docierają do Hotmail.
Więc w zasadzie to, co tu robię, to zmodyfikowanie obiektu phpmailer, załadowanie wiadomości do szablonu HTML i ustawienie jej na właściwość Body. Również wziąłem oryginalną wiadomość i ustawiłem właściwość AltBody.
źródło
Moim prostym rozwiązaniem jest użycie html2text https://github.com/soundasleep/html2text w następujący sposób:
Tutaj https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 także sedno.
źródło
Dla każdego, kto używa haka „phpmailer_init”, aby dodać własne „AltBody”:
Alternatywna treść tekstu jest ponownie wykorzystywana do wysyłania kolejnych wiadomości e-mail, chyba że usuniesz ją ręcznie! WordPress nie usuwa tego w wp_mail (), ponieważ nie oczekuje, że ta właściwość zostanie użyta.
Powoduje to, że odbiorcy mogą otrzymywać wiadomości, które nie są dla nich przeznaczone. Na szczęście większość osób korzystających z klientów pocztowych z obsługą HTML nie widzi wersji tekstowej, ale nadal jest to w zasadzie problem z bezpieczeństwem.
Na szczęście jest łatwa naprawa. Obejmuje to bit zastępczy altbody; zwróć uwagę, że potrzebujesz biblioteki PHP HTML2Text:
Oto także streszczenie wtyczki WP, którą zmodyfikowałem w celu rozwiązania tego problemu: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661
Niestety nie mogę komentować innych rozwiązań za pomocą wyżej wspomnianego haka, aby ich ostrzec, ponieważ nie mam jeszcze wystarczającej liczby przedstawicieli, aby skomentować.
źródło
to może nie być dokładna odpowiedź na początkowy post tutaj, ale jest to alternatywa dla niektórych tutaj przedstawionych rozwiązań dotyczących ustawiania alt body
Zasadniczo, musiałem (chciałem) ustawić odrębne altbody (tj. tekst jawny) dodatkowo do części HTML zamiast polegać na niektórych konwersjach / striptagach i tak dalej. więc wymyśliłem to, co wydaje się działać dobrze
źródło
Jeśli nie chcesz tworzyć konfliktu kodu w rdzeniu Wordpress, myślę, że alternatywnym lub najprostszym rozwiązaniem jest dodanie akcji,
phpmailer_init
która zrobi to przed faktycznym wysłaniem poczty wwp_mail
. Aby uprościć moje wyjaśnienie, zobacz poniższy przykład kodu:Jeśli dodasz zawartość do
AltBody
właściwości klasy PHPMailer, domyślny typ zawartości zostanie automatycznie ustawiony namultipart/alternative
.źródło