Zusammenfassung
Aufgrund eines Fehlers in WP Core führt das Senden von mehrteiligen E-Mails (HTML / Text) mit wp_mail () (um die Wahrscheinlichkeit zu verringern, dass E-Mails in Spam-Ordnern landen) ironischerweise dazu, dass Ihre Domain von Hotmail (und anderen Microsoft-E-Mails) blockiert wird.
Dies ist ein komplexes Problem, das ich detailliert aufschlüsseln möchte, um jemandem zu helfen, eine praktikable Lösung zu finden, die eventuell im Kern implementiert wird.
Es wird eine lohnende Lektüre. Lass uns anfangen...
Der Käfer
Der häufigste Rat, um zu vermeiden, dass Ihre Newsletter-E-Mails in Spam-Ordnern landen, ist das Senden von mehrteiligen Nachrichten.
Mehrteilig (MIME) bezeichnet das Senden eines HTML- und eines TEXT-Teils einer E-Mail-Nachricht in einer einzigen E-Mail. Wenn ein Client eine mehrteilige Nachricht empfängt, akzeptiert er die HTML-Version, wenn er HTML rendern kann, andernfalls wird die Nur-Text-Version angezeigt.
Dies hat sich bewährt. Beim Senden an Google Mail landeten alle unsere E-Mails in Spam-Ordnern, bis wir die Nachrichten in mehrteilig geändert haben, als sie in den Haupteingang eingingen. Tolles Zeug.
Wenn Sie jetzt mehrteilige Nachrichten über wp_mail () senden, wird der Inhaltstyp (multipart / *) zweimal ausgegeben, einmal mit Begrenzung (falls benutzerdefiniert festgelegt) und einmal ohne Begrenzung. Dieses Verhalten führt dazu, dass die E-Mail in einigen E-Mails, einschließlich aller Microsoft- E-Mails (Hotmail, Outlook usw.) , als unformatierte Nachricht und nicht mehrteilig angezeigt wird.
Microsoft kennzeichnet diese Nachricht als Junk und die wenigen eingehenden Nachrichten werden vom Empfänger manuell gekennzeichnet. Leider sind Microsoft-E-Mail-Adressen weit verbreitet. 40% unserer Abonnenten nutzen es.
Dies wird von Microsoft über einen kürzlich durchgeführten E-Mail-Austausch bestätigt.
Das Markieren der Nachrichten führt dazu, dass die Domain vollständig blockiert wird . Dies bedeutet, dass die Nachricht nicht an den Spam-Ordner gesendet wird, sondern überhaupt nicht an den Empfänger übermittelt wird .
Wir haben unsere Hauptdomain bisher dreimal blockieren lassen.
Da dies ein Fehler im WP-Core ist, wird jede Domäne, die mehrteilige Nachrichten sendet, blockiert. Das Problem ist, dass die meisten Webmaster nicht wissen warum. Ich habe dies bestätigt, als ich meine Nachforschungen anstellte und gesehen habe, wie andere Benutzer dies in Foren usw. diskutierten. Dazu muss ich mich mit dem Rohcode befassen und über die Funktionsweise dieser Art von E-Mail-Nachrichten Bescheid wissen, die wir als nächstes behandeln werden.
Lassen Sie es uns in Code zerlegen
Erstellen Sie ein Hotmail- / Outlook-Konto. Führen Sie dann den folgenden Code aus:
// 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 );
Und wenn Sie den Standardinhaltstyp ändern möchten , verwenden Sie:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Dadurch wird eine mehrteilige Nachricht gesendet.
Wenn Sie also die vollständige Rohdatenquelle der Nachricht überprüfen, werden Sie feststellen, dass der Inhaltstyp zweimal hinzugefügt wird, einmal ohne Begrenzung:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
Das ist das Problem.
Die Ursache des Problems liegt in pluggable.php
- wenn wir hier nachsehen:
// 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;
}
}
}
Potentielle Lösungen
Sie fragen sich also, warum Sie dies nicht bei trac gemeldet haben ? Habe ich schon . Zu meiner großen Überraschung wurde vor 5 Jahren ein anderes Ticket erstellt, das das gleiche Problem beschreibt.
Seien wir ehrlich, es ist ein halbes Jahrzehnt her. In Internetjahren ist das eher 30. Das Problem wurde eindeutig aufgegeben und wird im Grunde nie behoben (... es sei denn, wir lösen es hier).
Ich habe hier einen tollen Thread gefunden , der eine Lösung anbietet, aber während seine Lösung funktioniert, werden E-Mails ohne benutzerdefinierten $headers
Satz unterbrochen .
Dort stürzen wir jedes Mal ab. Entweder funktioniert die mehrteilige Version einwandfrei, und normale nicht festgelegte $headers
Nachrichten funktionieren nicht, oder Sie lesen einen Vers.
Die Lösung, die wir gefunden haben, war:
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 ) );
}
}
Ja, ich weiß, das Bearbeiten von Core-Dateien ist tabu, setzen Sie sich zurück ... Dies war eine verzweifelte Korrektur und ein schlechter Versuch, eine Korrektur für Core bereitzustellen.
Das Problem mit unserem Fix ist, dass Standard-E-Mails wie Neuanmeldungen, Kommentare, Zurücksetzen von Passwörtern usw. als leere Nachrichten zugestellt werden. Wir haben also ein funktionierendes wp_mail () Skript, das mehrteilige Nachrichten sendet, aber sonst nichts.
Was ist zu tun
Ziel ist es, mit der Kernfunktion wp_mail () (keine benutzerdefinierte sendmail-Funktion) sowohl normale ( Nur- Text-) als auch mehrteilige Nachrichten zu senden .
Wenn Sie versuchen, dieses Problem zu lösen, wird das Hauptproblem die Zeit sein, die Sie für das Senden von Dummy-Nachrichten, das Überprüfen des Empfangs und das Öffnen einer Schachtel mit Aspirin und das Anfluchen von Microsoft aufwenden müssen, weil Sie an deren gewöhnt sind IE Probleme, während der Gremlin hier leider WordPress ist.
Aktualisieren
Die von @bonger bereitgestellte Lösung kann $message
ein Array sein, das Alternativen mit Inhaltstyp enthält. Ich habe bestätigt, dass es in allen Szenarien funktioniert.
Wir werden zulassen, dass diese Frage offen bleibt, bis das Kopfgeld aufgebraucht ist, um das Bewusstsein für das Problem zu schärfen, möglicherweise bis zu einem Punkt, an dem es im Kern behoben wird. Fühlen Sie sich frei, eine alternative Lösung zu posten, bei der es $message
sich um eine Zeichenfolge handeln kann.
wp_mail()
Funktion steckbar ist, wird Ihr Ersatz nicht als ein Muss-Plugin definiert (in wp-content / mu-plugins). Dies ist keine gute Lösung für Sie (und alle anderen, die Core Fix nicht ausführen). In welchem Fall würde es$phpmailer->ContentType = $content_type;
nicht funktionieren, wenn die Multipart- / Boundary-Prüfung nach dem Festlegen (und nicht nach dem Elsing) nicht verschoben würde?wp_mail
ist steckbar . Kopiere die ursprüngliche Funktion in ein Plugin, bearbeite sie nach Bedarf und aktiviere das Plugin. WordPress verwendet Ihre bearbeitete Funktion anstelle der ursprünglichen, ohne dass Sie den Kern bearbeiten müssen.Antworten:
Die folgende Version von enthält
wp_mail()
den Patch von @ rmccue / @ MattyRob im Ticket https://core.trac.wordpress.org/ticket/15448 , der für 4.2.2 aktualisiert wurde$message
und ein Array mit dem Inhaltstyp sein kann getastete Alternativen:Wenn Sie das also in Ihre Datei "wp-content / mu-plugins / functions.php" einfügen, wird die WP-Version überschrieben. Es hat eine nette Verwendung, ohne mit Überschriften herumzuspielen, zB:
Bitte beachten Sie, dass ich dies nicht mit aktuellen E-Mails getestet habe ...
quelle
Dies ist überhaupt kein WordPress-Fehler, sondern ein Fehler, bei dem
phpmailer
benutzerdefinierte Header nicht berücksichtigt werden ... wenn Sie sich Folgendes ansehenclass-phpmailer.php
:Sie können sehen, dass der fehlerhafte Standardfall die Ausgabe der zusätzlichen Kopfzeile mit Zeichensatz und ohne Begrenzung ist. Das Setzen des Inhaltstyps per Filter löst dies nicht von selbst, nur weil der
alt
hier eingestellte Fallmessage_type
durch AktivierenAltBody
nicht leer ist, sondern der Inhaltstyp.Am Ende bedeutet dies
AltBody
, dass der Fehler umgangen werden sollte, sobald Sie eine Datei oder ein Inline-Bild anhängen oder das setzen . Dies bedeutet auch, dass der Inhaltstyp nicht explizit festgelegt werden muss, da er, sobald er vorhanden istAltBody
,multipart/alternative
von festgelegt wirdphpmailer
.Die einfache Antwort lautet also:
Dann müssen Sie die Überschriften nicht explizit setzen, sondern können einfach Folgendes tun:
Leider sind viele der Funktionen und Eigenschaften in der
phpmailer
Klasse geschützt. Wenn dies nicht der Fall ist, besteht eine gültige Alternative darin, dieMIMEHeaders
Eigenschaftphpmailer_init
vor dem Senden einfach über den Hook zu überprüfen und zu überschreiben .quelle
Ich habe gerade ein Plugin veröffentlicht , mit dem Benutzer HTML-Vorlagen für WordPress verwenden können und ich spiele gerade mit der Dev-Version , um einen einfachen Text-Fallback hinzuzufügen. Ich habe Folgendes ausgeführt und in meinen Tests wurde nur eine Grenze hinzugefügt, und E-Mails gehen einwandfrei bei Hotmail ein.
Im Grunde ändere ich hier also das phpmailer-Objekt, lade die Nachricht in eine HTML-Vorlage und setze sie auf die Body-Eigenschaft. Außerdem habe ich die ursprüngliche Nachricht genommen und die AltBody-Eigenschaft festgelegt.
quelle
Meine einfache Lösung besteht darin, html2text https://github.com/soundasleep/html2text folgendermaßen zu verwenden :
Hier https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 auch eine Zusammenfassung.
quelle
Für alle, die den 'phpmailer_init'-Hook verwenden, um ihren eigenen' AltBody 'hinzuzufügen:
Der alternative Textkörper wird für verschiedene aufeinanderfolgende E-Mails wiederverwendet , es sei denn, Sie löschen ihn manuell! WordPress löscht es in wp_mail () nicht, da es nicht erwartet, dass diese Eigenschaft verwendet wird.
Dies führt dazu, dass Empfänger möglicherweise E-Mails erhalten, die nicht für sie bestimmt sind. Glücklicherweise können die meisten Leute, die HTML-fähige Mail-Clients verwenden, die Textversion nicht sehen, aber es ist im Grunde immer noch ein Sicherheitsproblem.
Zum Glück gibt es eine einfache Lösung. Dies beinhaltet das Altbody-Ersatzbit; Beachten Sie, dass Sie die Html2Text-PHP-Bibliothek benötigen:
Hier ist auch eine Liste für ein WP-Plugin, das ich geändert habe, um dieses Problem zu beheben: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661
Leider kann ich die anderen Lösungen, die den oben genannten Haken verwenden, nicht kommentieren, um sie davor zu warnen, da ich noch nicht genug Repräsentanten habe, um Kommentare abzugeben.
quelle
Dies ist möglicherweise keine exakte Antwort auf den ersten Beitrag hier, aber eine Alternative zu einigen der hier angebotenen Lösungen zum Festlegen eines alternativen Körpers
Im Wesentlichen musste (wollte) ich zusätzlich zum HTML-Teil einen eigenen Altbody (dh Klartext) setzen, anstatt mich auf einige Conversion / Striptags und so weiter zu verlassen. Also habe ich mir das ausgedacht, was gut zu funktionieren scheint
quelle
Wenn Sie keinen Codekonflikt im Wordpress-Kern erstellen möchten, besteht die alternative oder einfachste Lösung meiner Meinung nach darin, eine Aktion hinzuzufügen
phpmailer_init
, die vor dem eigentlichen Senden von E-Mails in der ausgeführt wirdwp_mail
. Um meine Erklärung zu vereinfachen, sehen Sie sich das folgende Codebeispiel an:Wenn Sie der PHPMailer-Klasseneigenschaft einen Inhalt hinzufügen, wird
AltBody
der Standard-Inhaltstyp automatisch auf festgelegtmultipart/alternative
.quelle