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 = "[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 );
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()
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?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.Respuestas:
La siguiente versión de
wp_mail()
es con el parche aplicado de @ rmccue / @ MattyRob en el ticket https://core.trac.wordpress.org/ticket/15448 , actualizado para 4.2.2, que permite$message
ser una matriz que contiene contenido de tipo alternativas con llave:Entonces, si lo coloca en su archivo "wp-content / mu-plugins / functions.php", por ejemplo, anulará la versión de WP. Tiene un buen uso sin perder el tiempo con los encabezados, por ejemplo:
Tenga en cuenta que no he probado esto con correos electrónicos reales ...
fuente
Esto no es realmente un error de WordPress, es
phpmailer
uno que no permite encabezados personalizados ... si nos fijamos enclass-phpmailer.php
:Puede ver que el caso por defecto ofensivo es lo que está generando la línea de encabezado adicional con juego de caracteres y sin límite. Establecer el tipo de contenido por filtro no resuelve esto por sí solo porque el
alt
caso aquí se activamessage_type
marcandoAltBody
no está vacío en lugar del tipo de contenido.Al final, lo que esto significa es que tan pronto como adjuntes un archivo o una imagen en línea, o configures el
AltBody
, el error ofensivo debería omitirse. También significa que no hay necesidad de establecer explícitamente el tipo de contenido porque tan pronto como haya un valorAltBody
establecidomultipart/alternative
porphpmailer
.Entonces la respuesta simple es:
Entonces no necesita configurar los encabezados explícitamente, simplemente puede hacer:
Desafortunadamente, muchas de las funciones y propiedades de la
phpmailer
clase están protegidas, de lo contrario, una alternativa válida sería simplemente verificar y anular laMIMEHeaders
propiedad a través delphpmailer_init
enlace antes de enviarla.fuente
Acabo de lanzar un complemento para permitir que los usuarios usen plantillas html en WordPress y estoy jugando ahora en la versión de desarrollo para agregar un respaldo de texto simple. Hice lo siguiente y en mis pruebas solo veo un límite agregado y los correos electrónicos llegan bien a Hotmail.
Entonces, básicamente, lo que hago aquí es modificar el objeto phpmailer, cargar el mensaje dentro de una plantilla html y establecerlo en la propiedad Body. También tomé el mensaje original y configuré la propiedad AltBody.
fuente
Mi solución simple es usar html2text https://github.com/soundasleep/html2text de esta manera:
Aquí https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 también una idea general.
fuente
Para cualquiera que esté usando el gancho 'phpmailer_init' para agregar su propio 'AltBody':
El cuerpo de texto alternativo se reutiliza para enviar diferentes correos consecutivos, ¡a menos que lo borre manualmente! WordPress no lo borra en wp_mail () porque no espera que se use esta propiedad.
Esto da como resultado que los destinatarios reciban correos potencialmente no destinados a ellos. Afortunadamente, la mayoría de las personas que usan clientes de correo habilitados para HTML no verán la versión de texto, pero sigue siendo básicamente un problema de seguridad.
Afortunadamente hay una solución fácil. Esto incluye el bit de reemplazo de altbody; tenga en cuenta que necesita la biblioteca PHP Html2Text:
Aquí también hay un resumen de un complemento WP que modifiqué para solucionar este problema: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661
Desafortunadamente, no puedo comentar sobre las otras soluciones que usan el gancho antes mencionado, para advertirles de esto, ya que aún no tengo suficiente representante para comentar.
fuente
Esto podría no ser una respuesta exacta a la publicación inicial aquí, pero es una alternativa a algunas de las soluciones aquí proporcionadas con respecto a la configuración de un cuerpo alternativo
esencialmente, necesitaba (quería) establecer un cuerpo alternativo distinto (es decir, texto sin formato) adicionalmente a la parte html en lugar de confiar en algunas conversiones / striptags y otras cosas. así que se me ocurrió esto que parece funcionar bien
fuente
Si no desea crear ningún conflicto de código en el núcleo de Wordpress, creo que la solución alternativa o más simple es agregar una acción
phpmailer_init
que se realice antes del envío real de correo en elwp_mail
. Para simplificar mi explicación, vea el siguiente ejemplo de código:Si agrega un contenido en la
AltBody
propiedad de clase PHPMailer, el tipo de contenido predeterminado se establecerá automáticamente enmultipart/alternative
.fuente