สรุป
เนื่องจากมีปัญหาใน WP หลักส่งmultipartอีเมล (HTML / ข้อความ) กับwp_mail () (เพื่อลดโอกาสของอีเมลสิ้นสุดในโฟลเดอร์สแปม) จะกระแนะกระแหนส่งผลกับโดเมนของคุณถูกบล็อกโดย Hotmail (และอีเมลอื่น ๆ ของ Microsoft)
นี่เป็นปัญหาที่ซับซ้อนซึ่งฉันจะตั้งเป้าหมายให้ละเอียดโดยละเอียดในความพยายามช่วยคนหาวิธีแก้ปัญหาที่ใช้การได้ซึ่งอาจนำไปใช้ในแกนกลางในที่สุด
มันจะเป็นการอ่านที่คุ้มค่า เอาล่ะ...
ข้อผิดพลาด
คำแนะนำที่พบบ่อยที่สุดในการหลีกเลี่ยงอีเมลจดหมายข่าวของคุณที่อยู่ในโฟลเดอร์สแปมคือการส่งข้อความหลายส่วน
หลายส่วน (mime) หมายถึงการส่งทั้งส่วน HTML และ TEXT ของข้อความอีเมลในอีเมลเดียว เมื่อไคลเอนต์ได้รับข้อความหลายส่วนก็ยอมรับเวอร์ชัน HTML หากมันสามารถแสดงผล HTML มิฉะนั้นจะแสดงรุ่นข้อความธรรมดา
นี่พิสูจน์แล้วว่าใช้ได้จริง เมื่อส่งไปที่ gmail อีเมลทั้งหมดของเราจะถูกส่งไปยังโฟลเดอร์สแปมจนกว่าเราจะเปลี่ยนข้อความเป็นหลายส่วนเมื่ออีเมลเหล่านั้นเข้าสู่กล่องจดหมายหลัก สิ่งที่ยอดเยี่ยม
ทีนี้เมื่อส่งข้อความแบบหลายส่วนผ่าน wp_mail () มันจะส่งออกประเภทเนื้อหา (หลายส่วน / *) สองครั้งโดยมีขอบเขต (ถ้าตั้งค่าแบบกำหนดเอง) และอีกครั้งโดยไม่มี ลักษณะการทำงานนี้ส่งผลให้อีเมลที่ถูกแสดงเป็นข้อความ raw และไม่ใช่ multipart ในบางอีเมลรวมถึงMicrosoft ทั้งหมด (Hotmail, Outlook, etc ... )
Microsoft จะทำเครื่องหมายข้อความนี้ว่าเป็นจดหมายขยะและผู้รับไม่กี่ข้อความที่ผ่านเข้ามาจะถูกทำเครื่องหมายด้วยตนเองโดยผู้รับ น่าเสียดายที่มีการใช้ที่อยู่อีเมล Microsoft อย่างกว้างขวาง 40% ของสมาชิกของเราใช้งาน
นี่คือการยืนยันโดย Microsoft ผ่านการแลกเปลี่ยนอีเมลที่เรามีเมื่อเร็ว ๆ นี้
การตั้งค่าสถานะของข้อความที่จะส่งผลให้มีโดเมนที่ถูกสมบูรณ์บล็อก ซึ่งหมายความว่าข้อความจะไม่ถูกส่งไปยังโฟลเดอร์สแปมพวกเขาจะไม่ถูกส่งไปยังผู้รับเลย
เราได้ปิดกั้นโดเมนหลักของเรา 3 ครั้งแล้ว
เนื่องจากนี่เป็นข้อผิดพลาดใน Core WP ทุกโดเมนที่ส่งข้อความหลายส่วนจะถูกบล็อก ปัญหาคือเว็บมาสเตอร์ส่วนใหญ่ไม่ทราบสาเหตุ ฉันยืนยันสิ่งนี้เมื่อทำการวิจัยของฉันและเห็นผู้ใช้รายอื่นคุยเรื่องนี้ในฟอรัม ฯลฯ มันต้องมีการตรวจสอบรหัสดิบและมีความรู้ที่ดีเกี่ยวกับการทำงานของข้อความอีเมลประเภทนี้ซึ่งเรากำลังจะไป ...
ลองแบ่งมันเป็นรหัส
สร้างบัญชี 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 );
และหากคุณต้องการเปลี่ยนประเภทเนื้อหาเริ่มต้นให้ใช้:
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;
}
}
}
โซลูชั่นที่มีศักยภาพ
ดังนั้นคุณสงสัยทำไมคุณไม่รายงานเรื่องนี้ที่trac ? ผมมีอยู่แล้ว สำหรับความประหลาดใจที่ยิ่งใหญ่ของฉันตั๋วที่แตกต่างถูกสร้างขึ้นเมื่อ 5 ปีก่อนโดยสรุปปัญหาเดียวกัน
เรามาเจอกันมันเป็นครึ่งทศวรรษแล้ว ในปีอินเทอร์เน็ตนั่นคือ 30 ปีปัญหานี้ถูกยกเลิกอย่างชัดเจนและโดยทั่วไปจะไม่ได้รับการแก้ไข (... เว้นแต่ว่าเราจะแก้ไขที่นี่)
ฉันพบเธรดที่ยอดเยี่ยมที่นี่เสนอวิธีแก้ไขปัญหา แต่ในขณะที่โซลูชันของเขาใช้งานได้มันจะแบ่งอีเมลที่ไม่มี$headers
ชุดกำหนดเอง
นั่นคือสิ่งที่เราผิดพลาดทุกครั้ง อาจเป็นรุ่นที่มีหลายส่วนทำงานได้ดีและ$headers
ข้อความที่ไม่ได้ตั้งค่าตามปกติไม่สามารถใช้งานได้
วิธีแก้ปัญหาที่เราพบคือ:
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 ) );
}
}
ใช่ฉันรู้แล้วการแก้ไขไฟล์หลักเป็นข้อห้ามนั่งลง ... นี่เป็นการแก้ไขที่สิ้นหวังและความพยายามที่ไม่ดีในการจัดหาการแก้ไขสำหรับคอร์
ปัญหาเกี่ยวกับการแก้ไขของเราคืออีเมลเริ่มต้นเช่นการลงทะเบียนใหม่ความคิดเห็นการรีเซ็ตรหัสผ่านเป็นต้นจะถูกส่งเป็นข้อความเปล่า ดังนั้นเราจึงมีสคริปต์ wp_mail () ที่จะส่งข้อความหลายส่วน แต่ไม่มีอะไรอื่น
สิ่งที่ต้องทำ
จุดประสงค์ที่นี่คือการหาวิธีการส่งทั้งข้อความปกติ (ข้อความธรรมดา) และข้อความแบบหลายส่วนโดยใช้ฟังก์ชั่น core wp_mail () (ไม่ใช่ฟังก์ชั่น sendmail แบบกำหนดเอง)
เมื่อพยายามที่จะแก้ปัญหานี้ปัญหาหลักที่คุณจะพบคือระยะเวลาที่คุณใช้ในการส่งข้อความจำลองตรวจสอบว่าพวกเขาได้รับและเปิดกล่องแอสไพรินและสาปแช่งที่ Microsoft เพราะคุณคุ้นเคยกับพวกเขา ปัญหา IE ในขณะที่ gremlin ที่นี่เป็นที่น่าเสียดายว่า WordPress
ปรับปรุง
โซลูชันที่โพสต์โดย @bonger อนุญาตให้$message
เป็นอาร์เรย์ที่มีการสลับคีย์ชนิดเนื้อหา ฉันยืนยันว่ามันใช้งานได้ในทุกสถานการณ์
เราจะอนุญาตให้คำถามนี้ยังคงเปิดอยู่จนกว่าเงินรางวัลจะหมดเพื่อสร้างการรับรู้เกี่ยวกับปัญหาอาจจะอยู่ในระดับที่จะได้รับการแก้ไขในแกนกลาง อย่าลังเลที่จะโพสต์โซลูชันทางเลือกซึ่ง$message
สามารถเป็นสตริงได้
wp_mail()
ฟังก์ชั่นที่เสียบได้ไม่ได้กำหนดว่าการเปลี่ยนของคุณเป็นปลั๊กอินที่ต้องใช้ (ใน wp-content / mu-plugins) ไม่ใช่วิธีแก้ปัญหาที่ดีสำหรับคุณ (และคนอื่น ๆ ในกรณีใดจะไม่ย้ายการตรวจสอบหลายส่วน / ขอบเขตไปที่หลังจากการตั้งค่า$phpmailer->ContentType = $content_type;
(แทนที่จะเป็นแบบอื่น) ไม่ทำงาน?