Resumen
Debido a un error en WP Core, el envío de correos electrónicos de varias partes (html / text) con wp_mail () (para reducir la posibilidad de que los correos electrónicos terminen en carpetas de spam) resultará irónicamente con el bloqueo de su dominio por Hotmail (y otros correos electrónicos de Microsoft).
Este es un problema complejo que trataré de analizar con gran detalle en un intento de ayudar a alguien a encontrar una solución viable que eventualmente se pueda implementar en el núcleo.
Será una lectura gratificante. Vamos a empezar...
El bicho
El consejo más común para evitar que los correos electrónicos de sus boletines terminen en carpetas de spam es enviar mensajes de varias partes.
Multi-parte (mime) se refiere al envío de una parte HTML y TEXT de un mensaje de correo electrónico en un solo correo electrónico. Cuando un cliente recibe un mensaje de varias partes, acepta la versión HTML si puede representar HTML; de lo contrario, presenta la versión de texto sin formato.
Esto está demostrado que funciona. Al enviar a gmail, todos nuestros correos electrónicos llegaron a carpetas de spam hasta que cambiamos los mensajes a multiparte cuando llegaron a la bandeja de entrada principal. Buena cosa.
Ahora, al enviar mensajes de varias partes a través de wp_mail (), genera el Tipo de contenido (multipart / *) dos veces, una con límite (si se configura de manera personalizada) y otra sin él. Este comportamiento da como resultado que el correo electrónico se muestre como un mensaje sin procesar y no con varias partes en algunos correos electrónicos, incluidos todos los de Microsoft (Hotmail, Outlook, etc.)
Microsoft marcará este mensaje como basura, y los pocos mensajes que lleguen serán marcados manualmente por el destinatario. Desafortunadamente , las direcciones de correo electrónico de Microsoft son ampliamente utilizadas. El 40% de nuestros suscriptores lo usan.
Esto es confirmado por Microsoft a través de un intercambio de correo electrónico que tuvimos recientemente.
El marcado de los mensajes dará como resultado que el dominio esté completamente bloqueado . Esto significa que el mensaje no se enviará a la carpeta de spam, ni siquiera se entregará al destinatario.
Hemos tenido nuestro dominio principal bloqueado 3 veces hasta ahora.
Debido a que este es un error en el núcleo de WP, todos los dominios que envían mensajes de varias partes están siendo bloqueados. El problema es que la mayoría de los webmasters no saben por qué. Lo he confirmado cuando investigo y veo a otros usuarios debatir esto en foros, etc. Requiere profundizar en el código sin procesar y tener un buen conocimiento de cómo funcionan este tipo de mensajes de correo electrónico, que vamos a ver a continuación ...
Vamos a dividirlo en código
Crea una cuenta hotmail / outlook. Luego, ejecute el siguiente código:
// 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 );
Y si desea cambiar el tipo de contenido predeterminado , use:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Esto enviará un mensaje multiparte.
Entonces, si verifica la fuente sin formato completa del mensaje, notará que el tipo de contenido se agrega dos veces, una vez sin límite:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
Ese es el problema.
La fuente del problema radica en pluggable.php
, si miramos aquí:
// 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;
}
}
}
Posibles soluciones
Entonces te preguntas, ¿por qué no has informado esto en trac ? Yo ya tengo . Para mi gran sorpresa, hace 5 años se creó un boleto diferente que describe el mismo problema.
Seamos realistas, ha pasado media década. En años de internet, eso es más como 30. El problema claramente ha sido abandonado y básicamente nunca se solucionará (... a menos que lo resolvamos aquí).
Encontré un excelente hilo aquí que ofrece una solución, pero aunque su solución funciona, rompe los correos electrónicos que no tienen un $headers
conjunto personalizado .
Ahí es donde nos estrellamos cada vez. O bien la versión multiparte funciona bien, y los $headers
mensajes normales no configurados no funcionan, o viceversa.
La solución que se nos ocurrió fue:
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 ) );
}
}
Sí, lo sé, la edición de archivos centrales es tabú, siéntate ... esta fue una solución desesperada y un intento pobre de proporcionar una solución para el núcleo.
El problema con nuestra solución es que los correos electrónicos predeterminados como nuevos registros, comentarios, restablecimiento de contraseña, etc. se enviarán como mensajes en blanco. Así que tenemos un script de trabajo wp_mail () que enviará mensajes multiparte pero nada más.
Qué hacer
El objetivo aquí es encontrar una manera de enviar mensajes normales (texto sin formato) y multiparte utilizando la función central wp_mail () (no una función de envío personalizada).
Cuando intente resolver esto, el principal problema que encontrará es la cantidad de tiempo que pasará enviando mensajes ficticios, verificando si se reciben y básicamente abriendo una caja de aspirina y maldiciendo a Microsoft porque está acostumbrado a su Problemas de IE mientras que el gremlin aquí es desafortunadamente WordPress.
Actualizar
La solución publicada por @bonger permite $message
ser una matriz que contiene alternativas con clave de tipo de contenido. He confirmado que funciona en todos los escenarios.
Permitiremos que esta pregunta permanezca abierta hasta que se agote la recompensa para crear conciencia sobre el problema, tal vez a un nivel en el que se solucionará en el núcleo. Siéntase libre de publicar una solución alternativa donde $message
pueda ser una cadena.
wp_mail
es conectable . Copie la función original en un complemento, edítela como lo necesite y active el complemento. WordPress usará su función editada en lugar de la original, sin necesidad de editar core.
wp_mail()
función es enchufable, ¿no está definiendo su reemplazo como un complemento de uso obligatorio (en wp-content / mu-plugins), no es una buena solución para usted (y para todos los demás, falla la corrección del núcleo)? ¿En qué caso no$phpmailer->ContentType = $content_type;
movería la verificación de múltiples partes / límites a después de la configuración (en lugar de eliminar) no funcionaría?