Sommaire
En raison d'un bogue dans WP de base, l' envoi multipart e - mails (html / texte) avec wp_mail () (pour réduire la chance d'e - mails qui se terminent dans les dossiers de spam) sera ironiquement résultat avec votre domaine bloqué par Hotmail (et d' autres e - mails Microsoft).
C’est un problème complexe que je vais tenter d’exploiter de manière très détaillée pour tenter d’aider une personne à trouver une solution viable pouvant éventuellement être mise en œuvre de manière centralisée.
Ce sera une lecture enrichissante. Commençons...
L'insecte
Le conseil le plus courant pour éviter que vos e-mails de bulletin d'information finissent dans des dossiers de courrier indésirable est d'envoyer des messages en plusieurs parties.
Multi-part (mime) fait référence à l'envoi simultané d'une partie HTML et d'une partie TEXT d'un message électronique. Lorsqu'un client reçoit un message en plusieurs parties, il accepte la version HTML s'il peut restituer le code HTML. Sinon, il présente la version en texte brut.
Ceci est prouvé pour fonctionner. Lors de l'envoi à gmail, tous nos courriels se retrouvaient dans des dossiers de courrier indésirable jusqu'à ce que nous changions les messages en plusieurs parties lorsqu'ils arrivaient dans la boîte de réception principale. Super truc.
Désormais, lors de l'envoi de messages en plusieurs parties via wp_mail (), le type de contenu (multipart / *) est généré deux fois, une fois avec une limite (si défini de manière personnalisée) et une fois sans. Ce comportement a pour résultat que l'e-mail est affiché en tant que message brut et non en plusieurs parties sur certains courriels, y compris tous les Microsoft (Hotmail, Outlook, etc.).
Microsoft signalera ce message comme courrier indésirable et les quelques messages reçus seront signalés manuellement par le destinataire. Malheureusement , les adresses électroniques de Microsoft sont largement utilisées. 40% de nos abonnés l'utilisent.
Ceci est confirmé par Microsoft via un échange de courrier électronique que nous avons eu récemment.
Le signalement des messages entraînera le blocage complet du domaine . Cela signifie que le message ne sera pas envoyé dans le dossier spam, ils ne seront même pas remis au destinataire.
Nous avons eu notre domaine principal bloqué 3 fois jusqu'à présent.
Comme il s’agit d’un bogue dans le noyau de WP, chaque domaine qui envoie des messages en plusieurs parties est bloqué. Le problème est que la plupart des webmasters ne savent pas pourquoi. Je l'ai confirmé lors de mes recherches et lorsque j'ai vu d'autres utilisateurs en discuter sur des forums, etc. Cela nécessite de fouiller dans le code brut et de bien connaître le fonctionnement de ce type de messages électroniques, que nous passons ensuite à ...
Décomposons en code
Créez un compte hotmail / outlook. Ensuite, exécutez le code suivant:
// 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 );
Et si vous souhaitez modifier le type de contenu par défaut , utilisez:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Cela enverra un message en plusieurs parties.
Ainsi, si vous vérifiez la source brute complète du message, vous remarquerez que le type de contenu est ajouté deux fois, une fois sans limite:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
C'est le problème.
La source du problème réside dans pluggable.php
- si nous regardons quelque part ici:
// 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;
}
}
}
Solutions potentielles
Vous vous demandez donc pourquoi vous n'avez pas signalé cela à Trac ? J'ai déjà . À ma grande surprise, un billet différent a été créé il y a 5 ans, soulignant le même problème.
Regardons les choses en face, cela fait une demi-décennie. Dans les années Internet, cela correspond plus à 30 ans. Le problème a clairement été abandonné et ne sera fondamentalement jamais résolu (... sauf si nous le résolvons ici).
J'ai trouvé ici un bon fil offrant une solution, mais si sa solution fonctionne, elle casse les courriers électroniques qui n'ont pas de $headers
configuration personnalisée .
C'est là que nous nous écrasons à chaque fois. Soit la version en plusieurs parties fonctionne bien, et les $headers
messages normaux non définis ne le sont pas, soit un verset.
La solution que nous avons trouvée était:
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 ) );
}
}
Oui, je sais, éditer des fichiers core est tabou, asseyez-vous… c’était un correctif désespéré et une mauvaise tentative de fournir un correctif pour le core.
Le problème avec notre solution est que les emails par défaut tels que les nouvelles inscriptions, les commentaires, la réinitialisation du mot de passe, etc. seront livrés sous forme de messages vierges. Nous avons donc un script de travail wp_mail () qui envoie des messages en plusieurs parties, mais rien d’autre.
Que faire
Le but ici est de trouver un moyen d’envoyer des messages normaux (texte brut) et multipart à l’aide de la fonction principale wp_mail () (et non d’une fonction sendmail personnalisée).
Lorsque vous tentez de résoudre ce problème, le principal problème que vous rencontrerez est le temps que vous passerez à envoyer des messages factices, à vérifier s'ils sont reçus et à ouvrir une boîte d'aspirine et à maudire Microsoft car vous êtes habitué à leurs messages. Problèmes IE alors que le gremlin ici est malheureusement WordPress.
Mise à jour
La solution publiée par @bonger permet $message
d’être un tableau contenant des substituts avec une clé de type contenu. J'ai confirmé que cela fonctionne dans tous les scénarios.
Nous laisserons cette question ouverte jusqu'à épuisement des primes pour sensibiliser le public au problème, peut - être à un niveau où elles seront résolues de manière fondamentale. N'hésitez pas à poster une solution alternative où $message
peut être une chaîne.
wp_mail()
fonction est connectable, votre remplaçant n'est pas défini comme un plug-in à utiliser absolument (dans wp-content / mu-plugins), ce n'est pas une bonne solution pour vous (et tous les autres, le correctif principal défaillant)? Dans quel cas le déplacement de la vérification multipartie / limite après réglage$phpmailer->ContentType = $content_type;
(plutôt que elsing) ne fonctionnerait-il pas?wp_mail
est connectable . Copiez la fonction originale dans un plugin, modifiez-la comme vous le souhaitez et activez le plugin. WordPress utilisera votre fonction modifiée au lieu de celle d'origine, sans avoir besoin de modifier le coeur.Réponses:
La version suivante de
wp_mail()
contient le correctif appliqué de @ rmccue / @ MattyRob dans le ticket https://core.trac.wordpress.org/ticket/15448 , actualisé pour la version 4.2.2, ce qui permet$message
de constituer un tableau contenant le type de contenu. remplaçants à clé:Donc, si vous le mettez dans votre fichier "wp-content / mu-plugins / functions.php", par exemple, il remplacera la version de WP. Il a un bon usage sans déconner avec les en-têtes, par exemple:
Veuillez noter que je n'ai pas testé cela avec les emails actuels ...
la source
Ce n'est pas vraiment un bogue WordPress, c'est un bogue
phpmailer
qui ne permet pas les en-têtes personnalisés ... si vous regardezclass-phpmailer.php
:Vous pouvez voir que le cas par défaut incriminé est la sortie de la ligne d’en-tête supplémentaire avec charset et aucune limite. La définition du type de contenu par filtre ne résout pas le problème en soi, car le
alt
cas est activémessage_type
en cochant que ceAltBody
n'est pas vide, mais plutôt le type de contenu.En fin de compte, cela signifie que dès que vous attachez un fichier ou une image en ligne, ou définissez-le
AltBody
, le bogue incriminé doit être ignoré. Cela signifie également qu'il n'est pas nécessaire de définir explicitement le type de contenu, car dès qu'il y en a un,AltBody
il est défini surmultipart/alternative
parphpmailer
.Donc, la réponse simple est:
Ensuite, vous n'avez pas besoin de définir explicitement les en-têtes, vous pouvez simplement faire:
Malheureusement, de nombreuses fonctions et propriétés de la
phpmailer
classe sont protégées. Sinon, une alternative valable serait simplement de vérifier et de remplacer laMIMEHeaders
propriété via le point d'phpmailer_init
ancrage avant de l'envoyer.la source
Je viens de publier un plug-in pour permettre aux utilisateurs d'utiliser des modèles HTML sur WordPress et je joue actuellement sur la version dev pour ajouter un simple repli de texte. J'ai fait ce qui suit et dans mes tests, je ne vois qu'une limite ajoutée et les courriels arrivent bien à Hotmail.
En gros, ce que je fais ici, c'est modifier l'objet phpmailer, charger le message dans un modèle html et le définir sur la propriété Body. De plus, j'ai pris le message d'origine et défini la propriété AltBody.
la source
Ma solution simple consiste à utiliser html2text https://github.com/soundasleep/html2text de cette façon:
Ici, https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 est également un élément essentiel.
la source
Pour ceux qui utilisent le hook 'phpmailer_init' pour ajouter leur propre 'AltBody':
Le corps de texte alternatif est réutilisé pour différents courriers consécutifs envoyés, à moins que vous ne le supprimiez manuellement! WordPress ne l'efface pas dans wp_mail () car il ne s'attend pas à ce que cette propriété soit utilisée.
Cela a pour conséquence que les destinataires reçoivent potentiellement des courriers qui ne leur sont pas destinés. Heureusement, la plupart des utilisateurs de clients de messagerie utilisant HTML ne verront pas la version texte, mais il s'agit toujours d'un problème de sécurité.
Heureusement, il y a une solution facile. Cela inclut le bit de remplacement altbody; notez que vous avez besoin de la bibliothèque PHP Html2Text:
Voici également l'essentiel d'un plugin WP que j'ai modifié pour résoudre ce problème: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661
Malheureusement, je ne peux pas commenter les autres solutions utilisant le crochet susmentionné, pour les en avertir, car je n'ai pas encore assez de représentants pour commenter.
la source
cela pourrait ne pas être une réponse exacte au message initial ici, mais c'est une alternative à certaines des solutions fournies ici concernant la définition d'un corps alt
Essentiellement, je devais (je voulais) définir un altbody distinct (c'est-à-dire un texte en clair) en plus de la partie html au lieu de compter sur des conversions / striptags et autres. donc je suis venu avec ce qui semble fonctionner très bien
la source
Si vous ne souhaitez pas créer de conflit de code dans le noyau de Wordpress, je pense que la solution la plus simple ou la solution la plus simple consiste à ajouter une action à
phpmailer_init
faire avant l'envoi effectif du courrier dans le fichierwp_mail
. Pour simplifier mon explication, voir l'exemple de code ci-dessous:Si vous ajoutez un contenu dans la
AltBody
propriété de la classe PHPMailer , le type de contenu par défaut sera automatiquement défini surmultipart/alternative
.la source