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 = "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 );
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?