Ringkasan
Karena bug di WP Core, mengirim email multi bagian (html / teks) dengan wp_mail () (untuk mengurangi kemungkinan email berakhir di folder spam) secara ironis akan mengakibatkan domain Anda diblokir oleh Hotmail (dan email Microsoft lainnya).
Ini adalah masalah kompleks yang akan saya uraikan dengan sangat rinci dalam upaya membantu seseorang menemukan solusi yang bisa diterapkan yang pada akhirnya dapat diterapkan pada intinya.
Ini akan menjadi bacaan yang bermanfaat. Mari kita mulai...
Serangga
Saran paling umum untuk menghindari email buletin Anda berakhir di folder spam adalah mengirim pesan multi bagian.
Multi-bagian (pantomim) mengacu pada mengirim bagian HTML dan TEXT dari pesan email dalam satu email. Ketika klien menerima pesan multi-bagian, ia menerima versi HTML jika dapat merender HTML, jika tidak, ia menyajikan versi teks biasa.
Ini terbukti berhasil. Saat mengirim ke gmail, semua email kami mendarat di folder spam hingga kami mengubah pesan menjadi multipart ketika mereka masuk ke kotak masuk utama. Hal yang bagus.
Sekarang, ketika mengirim pesan multi bagian melalui wp_mail (), ia menampilkan Jenis Konten (multi bagian / *) dua kali, sekali dengan batas (jika diatur secara khusus) dan sekali tanpa. Perilaku ini dihasilkan dengan email yang ditampilkan sebagai pesan mentah dan tidak multi-bagian pada beberapa email, termasuk semua Microsoft (Hotmail, Outlook, dll ...)
Microsoft akan menandai pesan ini sebagai sampah, dan beberapa pesan yang datang akan ditandai secara manual oleh penerima. Sayangnya , alamat email Microsoft banyak digunakan. 40% pelanggan kami menggunakannya.
Ini dikonfirmasi oleh Microsoft melalui pertukaran email yang kami miliki baru-baru ini.
Penandaan pesan akan mengakibatkan domain diblokir sepenuhnya . Ini berarti bahwa pesan tidak akan dikirim ke folder spam, mereka bahkan tidak akan dikirimkan ke penerima sama sekali.
Kami telah memblokir domain utama kami 3 kali sejauh ini.
Karena ini adalah bug di inti WP, setiap domain yang mengirim pesan multi bagian diblokir. Masalahnya adalah kebanyakan webmaster tidak tahu mengapa. Saya telah mengkonfirmasi ini ketika melakukan penelitian dan melihat pengguna lain mendiskusikan hal ini di forum, dll. Memerlukan menggali kode mentah dan memiliki pengetahuan yang baik tentang bagaimana jenis pesan email ini bekerja, yang akan kita bahas selanjutnya ...
Mari kita memecahnya menjadi kode
Buat akun hotmail / prospek. Kemudian, jalankan kode berikut:
// 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 );
Dan jika Anda ingin mengubah jenis konten default , gunakan:
add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
return 'multipart/alternative';
}
Ini akan mengirim pesan multi bagian.
Jadi, jika Anda memeriksa sumber mentah lengkap pesan, Anda akan melihat bahwa jenis konten ditambahkan dua kali, sekali tanpa batas:
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=
Itu masalahnya.
Sumber masalahnya terletak pada pluggable.php
- jika kita melihat ke suatu tempat di sini:
// 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;
}
}
}
Solusi potensial
Jadi Anda bertanya-tanya, mengapa Anda tidak melaporkan ini di trac ? Saya sudah punya . Yang sangat mengejutkan saya, tiket yang berbeda dibuat 5 tahun yang lalu menguraikan masalah yang sama.
Mari kita hadapi itu, sudah setengah dekade. Dalam tahun-tahun internet, itu lebih seperti 30. Masalahnya jelas telah ditinggalkan dan pada dasarnya tidak akan pernah diperbaiki (... kecuali jika kita menyelesaikannya di sini).
Saya menemukan utas yang bagus di sini menawarkan solusi, tetapi sementara solusinya bekerja, itu merusak email yang tidak memiliki $headers
set kustom .
Di situlah kita crash setiap saat. Versi multipart berfungsi dengan baik, dan $headers
pesan yang tidak disetel normal tidak berfungsi , atau sebaliknya.
Solusi yang kami temukan adalah:
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 ) );
}
}
Ya, saya tahu, mengedit file inti adalah hal yang tabu, duduk kembali ... ini adalah perbaikan yang putus asa dan upaya yang buruk untuk memberikan perbaikan untuk inti.
Masalah dengan perbaikan kami adalah bahwa email default seperti pendaftaran baru, komentar, reset kata sandi dll akan dikirimkan sebagai pesan kosong. Jadi kami memiliki skrip wp_mail () yang berfungsi yang akan mengirim pesan multi bagian tetapi tidak ada yang lain.
Melakukan apa
Tujuannya di sini adalah untuk menemukan cara untuk mengirim pesan normal (teks biasa) dan multi -bagian menggunakan fungsi inti wp_mail () (bukan fungsi sendmail khusus).
Ketika mencoba untuk menyelesaikan ini, masalah utama yang akan Anda temui adalah jumlah waktu yang akan Anda habiskan untuk mengirim pesan palsu, memeriksa apakah mereka diterima dan pada dasarnya membuka kotak aspirin dan memaki di Microsoft karena Anda terbiasa dengan mereka Masalah IE sementara GREMLIN di sini sayangnya WordPress.
Memperbarui
Solusi yang diposting oleh @bonger memungkinkan $message
untuk menjadi array yang berisi alternatif jenis konten yang dikunci. Saya telah mengkonfirmasi bahwa ini berfungsi di semua skenario.
Kami akan membiarkan pertanyaan ini tetap terbuka sampai hadiah habis untuk meningkatkan kesadaran tentang masalah, mungkin ke tingkat di mana ia akan diperbaiki pada intinya. Jangan ragu untuk mengirim solusi alternatif di mana $message
dapat berupa string.
wp_mail()
fungsi ini pluggable, tidak mendefinisikan pengganti Anda sebagai plugin yang harus digunakan (dalam wp-content / mu-plugins) bukan solusi yang baik untuk Anda (dan semua orang, gagal memperbaiki inti)? Dalam hal mana tidak akan memindahkan pemeriksaan multi bagian / batas setelah pengaturan$phpmailer->ContentType = $content_type;
(daripada elsing) tidak berfungsi?wp_mail
dapat dicolokkan . Salin fungsi asli dalam sebuah plugin, edit sesuai kebutuhan dan aktifkan plugin tersebut. WordPress akan menggunakan fungsi yang diedit alih-alih yang asli, tanpa perlu mengedit inti.Jawaban:
Versi berikut
wp_mail()
adalah dengan tambalan @ rmccue / @ MattyRob di tiket https://core.trac.wordpress.org/ticket/15448 , disegarkan untuk 4.2.2, yang memungkinkan$message
untuk menjadi array yang berisi tipe-konten. alternatif yang dikunci:Jadi, jika Anda memasukkannya ke dalam file mis. "Wp-content / mu-plugins / functions.php" Anda, maka itu akan menggantikan versi WP. Ini memiliki penggunaan yang bagus tanpa bermain-main dengan header, misalnya:
Harap dicatat saya belum menguji ini dengan email yang sebenarnya ...
sumber
Ini bukan bug WordPress sama sekali, ini adalah bug yang
phpmailer
tidak memungkinkan header kustom ... jika Anda melihatclass-phpmailer.php
:Anda dapat melihat kasus default yang menyinggung adalah apa yang mengeluarkan baris header tambahan dengan charset dan tanpa batas. Mengatur jenis konten berdasarkan filter tidak menyelesaikannya dengan sendirinya hanya karena
alt
case di sini diaktifkanmessage_type
dengan memeriksaAltBody
tidak kosong daripada jenis konten.Pada akhirnya apa artinya ini segera setelah Anda melampirkan file atau gambar sebaris, atau mengatur
AltBody
, bug yang menyinggung harus dilewati. Ini juga berarti tidak perlu secara eksplisit mengatur jenis konten karena segera setelahAltBody
itu diaturmultipart/alternative
olehphpmailer
.Jadi jawaban sederhananya adalah:
Maka Anda tidak perlu mengatur tajuk secara eksplisit, Anda cukup melakukannya:
Sayangnya banyak fungsi dan properti di
phpmailer
kelas dilindungi, jika bukan karena itu alternatif yang valid adalah dengan hanya memeriksa dan menimpaMIMEHeaders
properti melaluiphpmailer_init
hook sebelum mengirim.sumber
Saya baru saja merilis sebuah plugin untuk memungkinkan pengguna menggunakan templat html di WordPress dan saya bermain sekarang di versi dev untuk menambahkan fallback teks sederhana. Saya melakukan yang berikut dan dalam pengujian saya, saya hanya melihat satu batas ditambahkan dan email diterima dengan baik untuk Hotmail.
Jadi pada dasarnya yang saya lakukan di sini adalah memodifikasi objek phpmailer, memuat pesan di dalam template html dan mengaturnya ke properti Body. Saya juga mengambil pesan asli dan mengatur properti AltBody.
sumber
Solusi sederhana saya adalah dengan menggunakan html2text https://github.com/soundasleep/html2text dengan cara ini:
Di sini https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 juga merupakan intisari.
sumber
Bagi siapa pun yang menggunakan kait 'phpmailer_init' untuk menambahkan 'AltBody' mereka sendiri:
Badan teks alternatif digunakan kembali untuk berbagai email berturut-turut yang dikirim, kecuali Anda menghapusnya secara manual! WordPress tidak menghapusnya di wp_mail () karena tidak mengharapkan properti ini digunakan.
Ini menghasilkan penerima yang berpotensi menerima email yang tidak dimaksudkan untuk mereka. Untungnya sebagian besar orang yang menggunakan klien email yang mendukung HTML tidak akan melihat versi teks, tetapi pada dasarnya ini masih merupakan masalah keamanan.
Untungnya ada perbaikan yang mudah. Ini termasuk bit pengganti altbody; perhatikan bahwa Anda membutuhkan pustaka PHP Html2Text:
Berikut juga inti untuk plugin WP yang saya modifikasi untuk memperbaiki masalah ini: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661
Sayangnya saya tidak dapat mengomentari solusi lain menggunakan kait yang disebutkan di atas, untuk memperingatkan mereka tentang hal ini, karena saya belum memiliki perwakilan yang cukup untuk berkomentar.
sumber
ini mungkin bukan jawaban yang tepat untuk posting awal di sini, tapi ini merupakan alternatif dari beberapa solusi yang disediakan di sini mengenai pengaturan alt body
pada dasarnya, saya perlu (ingin) mengatur altbody yang berbeda (yaitu plaintext) tambahan ke bagian html daripada mengandalkan beberapa konversi / striptag dan yang lainnya. jadi saya datang dengan ini yang tampaknya berfungsi dengan baik
sumber
Jika Anda tidak ingin membuat konflik kode apa pun di inti Wordpress, saya pikir alternatif atau solusi paling sederhana adalah menambahkan tindakan
phpmailer_init
yang akan dilakukan sebelum pengiriman surat yang sebenarnya diwp_mail
. Untuk menyederhanakan penjelasan saya lihat contoh kode di bawah ini:Jika Anda menambahkan konten di
AltBody
properti kelas PHPMailer maka jenis konten default secara otomatis akan diatur kemultipart/alternative
.sumber