Sumário
Devido a um erro no WP Core, o envio de emails com várias partes (html / text) com wp_mail () (para reduzir a chance de emails terminarem em pastas de spam) ironicamente resultará em seu domínio ser bloqueado pelo Hotmail (e outros emails da Microsoft).
Esse é um problema complexo que tentarei detalhar em detalhes, na tentativa de ajudar alguém a encontrar uma solução viável que possa eventualmente ser implementada no núcleo.
Será uma leitura gratificante. Vamos começar...
O inseto
O conselho mais comum para evitar que os emails de seu boletim acabem nas pastas de spam é enviar mensagens com várias partes.
Múltiplas partes (mime) refere-se ao envio de uma parte HTML e TEXT de uma mensagem de email em um único email. Quando um cliente recebe uma mensagem com várias partes, ele aceita a versão HTML se puder renderizar HTML; caso contrário, apresenta a versão em texto sem formatação.
Está provado que isso funciona. Ao enviar para o gmail, todos os nossos emails foram parar em pastas de spam até mudarmos as mensagens para multipartes quando chegaram à caixa de entrada principal. Coisas boas.
Agora, ao enviar mensagens com várias partes via wp_mail (), ele gera o Tipo de conteúdo (multipart / *) duas vezes, uma com limite (se definido de maneira personalizada) e uma vez sem. Esse comportamento resulta com o email sendo exibido como uma mensagem bruta e não com várias partes em alguns emails, incluindo todos os Microsoft (Hotmail, Outlook, etc ...)
A Microsoft sinalizará esta mensagem como lixo eletrônico e as poucas mensagens enviadas serão sinalizadas manualmente pelo destinatário. Infelizmente , os endereços de email da Microsoft são amplamente usados. 40% dos nossos assinantes usam.
Isso é confirmado pela Microsoft por meio de uma troca de e-mails que tivemos recentemente.
A sinalização das mensagens resultará com o domínio sendo completamente bloqueado . Isso significa que a mensagem não será enviada para a pasta de spam, nem será entregue ao destinatário.
Até agora, nosso domínio principal foi bloqueado três vezes.
Como esse é um bug no núcleo do WP, todos os domínios que enviam mensagens com várias partes estão sendo bloqueados. O problema é que a maioria dos webmasters não sabe o porquê. Confirmei isso ao fazer minha pesquisa e ver outros usuários discutindo isso em fóruns, etc. Isso exige que você se aprofunde no código bruto e tenha um bom conhecimento de como esse tipo de mensagem de email funciona, o que vamos seguir ...
Vamos dividi-lo em código
Crie uma conta do hotmail / outlook. Em seguida, execute o seguinte 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 );
E se você deseja alterar o tipo de conteúdo padrão , use:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Isso enviará uma mensagem com várias partes.
Portanto, se você verificar a fonte bruta completa da mensagem, notará que o tipo de conteúdo é adicionado duas vezes, uma vez sem limite:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
Essa é a questão.
A fonte do problema está pluggable.php
- se olharmos para algum lugar aqui:
// 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;
}
}
}
Soluções potenciais
Então você está se perguntando, por que você não relatou isso no trac ? Eu já tenho . Para minha grande surpresa, um bilhete diferente foi criado há 5 anos, descrevendo o mesmo problema.
Vamos ser sinceros, já faz meia década. Nos anos da internet, isso é mais ou menos 30. O problema foi claramente abandonado e basicamente nunca será resolvido (... a menos que se o resolvamos aqui).
Encontrei um ótimo tópico aqui oferecendo uma solução, mas enquanto a solução funciona, ele quebra e-mails que não têm um $headers
conjunto personalizado .
É aí que batemos toda vez. A versão multipartes funciona bem, e as $headers
mensagens não configuradas normais não funcionam ou vice-versa.
A solução que encontramos foi:
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 ) );
}
}
Sim, eu sei, editar arquivos principais é um tabu, sente-se ... essa foi uma correção desesperada e uma tentativa pobre de fornecer uma correção para o núcleo.
O problema com nossa correção é que os emails padrão, como novos registros, comentários, redefinição de senha, etc. serão entregues como mensagens em branco. Portanto, temos um script wp_mail () que envia mensagens com várias partes, mas nada mais.
O que fazer
O objetivo aqui é encontrar uma maneira de enviar mensagens normais (texto sem formatação) e multipartes usando a função principal wp_mail () (não uma função personalizada do sendmail).
Ao tentar resolver isso, o principal problema que você encontrará é a quantidade de tempo que você gastará no envio de mensagens falsas, verificando se elas são recebidas e basicamente abrindo uma caixa de aspirina e xingando na Microsoft porque você está acostumado a isso. Problemas do IE enquanto o gremlin aqui é infelizmente o WordPress.
Atualizar
A solução publicada por @bonger permite $message
ser uma matriz que contém alternativas com chave do tipo de conteúdo. Eu confirmei que funciona em todos os cenários.
Permitiremos que essa questão permaneça em aberto até que a recompensa acabe, para aumentar a conscientização sobre o problema, talvez até um nível em que ele seja fixado no núcleo. Sinta-se à vontade para postar uma solução alternativa onde $message
possa ser uma string.
wp_mail()
função é conectável, a definição de sua substituição como um plug-in obrigatório (no wp-content / mu-plugins) não é uma boa solução para você (e para todos os outros, com falha na correção do núcleo)? Nesse caso, não mover a verificação multipartes / limite para depois da configuração$phpmailer->ContentType = $content_type;
(em vez de excluir) não funcionaria?