摘要
由于WP Core中的错误,发送multipart 电子邮件(html/文本)wp_mail() (为了减少电子邮件进入垃圾邮件文件夹的可能性)具有讽刺意味的是,你的域名会被Hotmail(和其他Microsoft电子邮件)阻止。这是一个复杂的问题,我将对其进行详细分析,以帮助他人找到一个可行的解决方案,最终可能在core中实现。
It\'s going to be a rewarding read. Let\'s begin...
错误
避免新闻稿电子邮件被垃圾文件夹截留的最常见建议是发送多部分邮件。多部分(mime)是指在一封电子邮件中同时发送电子邮件的HTML和文本部分。当客户端接收到多部分消息时,如果它可以呈现HTML,则它接受HTML版本,否则它将呈现纯文本版本。
这被证明是有效的。在发送到gmail时,我们所有的电子邮件都会被放在垃圾邮件文件夹中,直到我们将邮件发送到主收件箱时改为多部分邮件。很棒的东西。
现在,当通过wp\\u mail()发送多部分消息时,它会输出两次内容类型(multipart/*),一次带边界(如果自定义设置),一次不带边界。这种行为导致电子邮件显示为原始消息,而不是在某些电子邮件上显示为多部分,包括all Microsoft(Hotmail、Outlook等)
Microsoft将此邮件标记为垃圾邮件,收件人将手动标记收到的少数邮件<不幸的是,Microsoft电子邮件地址被广泛使用。40%的用户使用它。
微软最近通过电子邮件交流证实了这一点。
标记消息将导致域完全blocked. 这意味着邮件不会发送到垃圾邮件文件夹,they will not even be delivered 致收件人。
到目前为止,我们的主域名已经被屏蔽了3次。
因为这是WP核心中的一个bug,every 正在阻止发送多部分消息的域。问题是大多数站长不知道为什么。我在做研究和看到其他用户在论坛上讨论这一点时已经证实了这一点。这需要深入研究原始代码,并对这些类型的电子邮件如何工作有很好的了解,我们接下来将继续。。。
让我们将其分解为代码,创建一个hotmail/outlook帐户。然后,运行以下代码:
// 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 );
如果你想改变default content type, 使用:add_filter( \'wp_mail_content_type\', \'set_content_type\' );
function set_content_type( $content_type ) {
return \'multipart/alternative\';
}
这将发送一条多部分消息。因此,如果检查消息的完整原始源,您会注意到内容类型添加了两次,一次没有边界:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
这就是问题所在。问题的根源在于pluggable.php
- 如果我们看看这里的某个地方:
// 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;
}
}
}
潜在的解决方案,why have you not reported this at trac? 我already have. 令我大吃一惊的是different ticket 创建于5年前,概述了相同的问题。让我们面对现实吧,已经五年了。在互联网时代,这更像是30岁。这个问题显然已经被抛弃,基本上永远不会得到解决(……除非我们在这里解决它)。
我找到了一个很棒的thread here 提供了一个解决方案,但虽然他的解决方案有效,但它会中断没有自定义的电子邮件$headers
设置
那就是我们每次撞车的地方。要么多部分版本工作正常,要么正常取消设置$headers
信息不会,或是用V字形表示诗句。
我们提出的解决方案是:
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 ) );
}
}
是的,我知道,编辑核心文件是禁忌,坐下。。。这是一个绝望的修复,也是为core提供修复的拙劣尝试。我们解决的问题是,新注册、评论、密码重置等默认电子邮件将作为空白消息发送。因此,我们有一个工作中的wp\\u mail()脚本,它将发送多部分消息,而不发送其他消息。
要做的是找到一种发送普通(纯文本)和多部分消息的方法using the core wp_mail() function (不是自定义sendmail功能)。
当你试图解决这个问题时,你会遇到的主要问题是,你会花大量时间发送虚假消息,检查是否收到这些消息,基本上打开一盒阿斯匹林,诅咒微软,因为你习惯了他们的IE问题,而这里的小精灵不幸是WordPress。
更新@bonger发布的解决方案允许$message
是一个包含内容类型键控交替的数组。我已经证实,它在所有情况下都有效。
我们会让这个问题一直悬而未决,直到赏金耗尽,以提高人们对这个问题的认识,maybe to a level where it will be fixed in core. 请随时发布替代解决方案,其中$message
可以是字符串。