Çok parçalı (text / html) e-postaların wp_mail () üzerinden gönderilmesi etki alanınızın yasaklanmasına neden olacak


37

özet

Çünkü gönderen WP Çekirdek bir hata, bir çok parçalı olan e-postalar (html / metin) wp_mail () (istenmeyen klasörleri içinde biten e-postalar olasılığını azaltmak için) olacaktır ironik alan adı Hotmail (ve diğer Microsoft e-postalar) tarafından engellenmiş olan sonuçlanır.

Bu, birinin özünde sonunda uygulanabilecek uygulanabilir bir çözüm bulmasına yardımcı olmak amacıyla, ayrıntılı olarak parçalara ayırmayı hedefleyeceğim karmaşık bir sorundur.

Ödüllendirici bir okuma olacak. Hadi başlayalım...

Böcek

Bülteninizin e-postalarının spam klasörlerinde sona ermesini önlemek için en yaygın tavsiye, çok parçalı iletiler göndermektir.

Çok parçalı (mime), bir e-posta mesajının hem HTML hem de METİN kısmını tek bir e-posta ile göndermeyi ifade eder. Bir istemci çok parçalı bir mesaj aldığında, HTML oluşturabilirse HTML sürümünü kabul eder, aksi halde düz metin sürümünü sunar.

Bu iş kanıtlanmış. Gmail’e gönderirken, tüm e-postalarımız ana gelen kutusuna geldiklerinde iletileri çok parçalı olarak değiştirinceye kadar spam klasörlerine indi. Harika şeyler.

Şimdi, wp_mail () üzerinden çok parçalı mesajlar gönderilirken, İçerik Türünü (çok parçalı / *) iki kez, bir kez sınırla (özel olarak ayarlanmışsa) ve bir kez de çıktı olarak verir. Bu davranış, e-postanın ham bir mesaj olarak görüntülenmesine ve tüm Microsoft (Hotmail, Outlook vb. Gibi) bazı e-postalarda çok parçalı olmamasına neden olur.

Microsoft bu mesajı önemsiz olarak işaretler ve gelen birkaç mesaj alıcı tarafından manuel olarak işaretlenir. Ne yazık ki , Microsoft e-posta adresleri yaygın olarak kullanılmaktadır. Abonelerimizin% 40'ı kullanıyor.

Bu, yakın zamanda sahip olduğumuz bir e-posta alışverişi yoluyla Microsoft tarafından onaylandı.

Mesajların işaretlenmesi, alanın tamamen bloke olmasıyla sonuçlanacaktır . Bu, mesajın spam klasörüne gönderilmeyeceği , alıcıya bile teslim edilmeyeceği anlamına gelir .

Ana etki alanımız şimdiye kadar 3 kez engellendi.

Bu WP çekirdeğinde bir hata olduğundan, çok parçalı mesajlar gönderen her alan engelleniyor. Sorun şu ki çoğu webmaster nedenini bilmiyor. Araştırmamı yaptığım ve forumlardaki vb. Tartışan diğer kullanıcıları gördüğümde bunu doğruladım. Ham koda girmeyi ve bu tür e-posta iletilerinin nasıl çalıştığı hakkında iyi bir bilgiye sahip olmayı gerektirir.

Hadi koda koyalım

Bir hotmail / outlook hesabı oluşturun. Ardından, aşağıdaki kodu çalıştırın:

// 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 );

Varsayılan içerik türünü değiştirmek istiyorsanız , şunu kullanın:

add_filter( 'wp_mail_content_type', 'set_content_type' );
function set_content_type( $content_type ) {
    return 'multipart/alternative';
}

Bu çok parçalı bir mesaj gönderir.

Dolayısıyla, mesajın tüm kaynak kodunu kontrol ederseniz, içerik türünün bir kez sınırlama olmadan iki kez eklendiğini fark edeceksiniz:

MIME-Version: 1.0
Content-Type: multipart/alternative;
         boundary="====f230673f9d7c359a81ffebccb88e5d61=="
MIME-Version: 1.0
Content-Type: multipart/alternative; charset=

Sorun bu.

Sorunun kaynağı yatıyor pluggable.php- eğer burada bir yere bakarsak:

// 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;
            }
        }
    }

Potansiyel çözümler

Merak ediyorsun, neden bunu Trac'te bildirmedin ? Bende zaten var . Benim için büyük sürpriz bir farklı bilet 5 yıl aynı sorunu özetleyen önce oluşturuldu.

Kabul edelim, yarım on yıl oldu. İnternet yıllarında, bu daha çok 30'a benziyor. Sorun açıkça terk edildi ve temelde asla çözülmeyecek (… burada çözemezsek).

Burada bir çözüm öneren harika bir konu buldum , ancak çözümü işe yarıyorken, özel $headersayarları olmayan e-postaları kırıyor .

Her seferinde kaza yaptığımız yer burasıdır. Çok parçalı sürüm iyi çalışıyor ve normal olarak ayarlanmamış $headersmesajlar çalışmıyor ya da ayeti yok.

Karşılaştığımız çözüm şuydu:

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 ) );
    }

}

Evet, biliyorum, çekirdek dosyaları düzenlemek tabudur, arkanıza yaslanın ... bu çaresiz bir düzeltme ve çekirdek için bir düzeltme sağlamak için kötü bir girişimdi.

Düzeltmemizdeki sorun, yeni kayıtlar, yorum, şifre sıfırlama vb. Gibi varsayılan e-postaların boş mesajlar olarak gönderilmesidir. Böylece, çok parçalı mesajlar gönderecek ancak başka bir şey göndermeyecek çalışan bir wp_mail () betiğimiz var.

Ne yapalım

Buradaki amaç , çekirdek wp_mail () işlevini (özel bir sendmail işlevi değil ) kullanarak hem normal (düz metin) hem de çok parçalı iletiler göndermenin bir yolunu bulmaktır .

Bunu çözmeye çalışırken, karşılaşacağınız asıl sorun, sahte mesajlar göndermek, alıp almadıklarını kontrol etmek ve temelde bir aspirin kutusu açmak ve Microsoft'ta küfür etmek için harcayacağınız zamandır. IE gremlin burada ne yazık ki WordPress ise sorunları.

Güncelleme

@Bonger tarafından yayınlanan çözüm $message, içerik tipi anahtarlı alternatifler içeren bir dizi olmasına izin verir . Tüm senaryolarda işe yaradığını onayladım.

Bu sorunun, sorunla ilgili farkındalığı artırmak için, belki de çekirdeğin sabitleneceği bir seviyeye gelene kadar açık kalmasına izin vereceğiz. $messageBir dize olabilir alternatif bir çözüm göndermek için çekinmeyin .


1
Olarak wp_mail() işlev size (ve herkes, başarısız çekirdek düzeltme) için iyi bir çözüm değildir fişlidir (wp-content / mu-plugins) mutlaka kullanılması eklentisi olarak değiştirilmesini tanımlayan değil? Bu durumda, çok parçalı / sınır kontrolünü ayardan sonra ayarlamaya $phpmailer->ContentType = $content_type;(hareket etmektense) hareket ettirmek işe yaramaz mıydı?
bonger

@bonger Lütfen çözümünüzü ayrıntılandıran bir cevap yazabilir misiniz?
Christine Cooper

1
Çünkü Yo, düzenleme çekirdek gerekmez wp_mailolduğunu takılabilir . Orijinal işlevi bir eklentiye kopyalayın, istediğiniz gibi düzenleyin ve eklentiyi etkinleştirin. WordPress, düzenlenmiş işlevinizi orijinal yerine kullanmak üzere kullanır ve çekirdek düzenlemeye gerek kalmaz.
gmazzap

@ChristineCooper Bunu test etmek gibi bir kraliyet acısı olduğunu söylediğin gibi yapmaktan çekinirim , ancak tracte @ rmccue / @ MattyRob tarafından önerilen gerçekten güzel bir yol gibi görünen yamalı devam et, buna dayanarak test edilmemiş bir cevap
göndereceğim

2
@ChristineCooper Eğer basit bir phpmailer içine kanca ve $ phpmailer-> AltBody metin gövdesini ayarlamak eğer aynı hata olur?
chifliiiii,

Yanıtlar:


15

Aşağıdaki sürüm, https://core.trac.wordpress.org/ticket/15448wp_mail() biletindeki 4.2.2 için yenilenmiş, içerik türünü içeren bir dizinin oluşturulmasına izin veren @ rmccue / @ MattyRob adlı düzeltme eki ile birlikte verilmiştir. anahtarlı alternatifler:$message

/**
 * Send mail, similar to PHP's mail
 *
 * A true return value does not automatically mean that the user received the
 * email successfully. It just only means that the method used was able to
 * process the request without any errors.
 *
 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
 * creating a from address like 'Name <email@address.com>' when both are set. If
 * just 'wp_mail_from' is set, then just the email address will be used with no
 * name.
 *
 * The default content type is 'text/plain' which does not allow using HTML.
 * However, you can set the content type of the email by using the
 * 'wp_mail_content_type' filter.
 *
 * If $message is an array, the key of each is used to add as an attachment
 * with the value used as the body. The 'text/plain' element is used as the
 * text version of the body, with the 'text/html' element used as the HTML
 * version of the body. All other types are added as attachments.
 *
 * The default charset is based on the charset used on the blog. The charset can
 * be set using the 'wp_mail_charset' filter.
 *
 * @since 1.2.1
 *
 * @uses PHPMailer
 *
 * @param string|array $to Array or comma-separated list of email addresses to send message.
 * @param string $subject Email subject
 * @param string|array $message Message contents
 * @param string|array $headers Optional. Additional headers.
 * @param string|array $attachments Optional. Files to attach.
 * @return bool Whether the email contents were sent successfully.
 */
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
    // Compact the input, apply the filters, and extract them back out

    /**
     * Filter the wp_mail() arguments.
     *
     * @since 2.2.0
     *
     * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
     *                    subject, message, headers, and attachments values.
     */
    $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );

    if ( isset( $atts['to'] ) ) {
        $to = $atts['to'];
    }

    if ( isset( $atts['subject'] ) ) {
        $subject = $atts['subject'];
    }

    if ( isset( $atts['message'] ) ) {
        $message = $atts['message'];
    }

    if ( isset( $atts['headers'] ) ) {
        $headers = $atts['headers'];
    }

    if ( isset( $atts['attachments'] ) ) {
        $attachments = $atts['attachments'];
    }

    if ( ! is_array( $attachments ) ) {
        $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
    }
    global $phpmailer;

    // (Re)create it, if it's gone missing
    if ( ! ( $phpmailer instanceof PHPMailer ) ) {
        require_once ABSPATH . WPINC . '/class-phpmailer.php';
        require_once ABSPATH . WPINC . '/class-smtp.php';
        $phpmailer = new PHPMailer( true );
    }

    // Headers
    if ( empty( $headers ) ) {
        $headers = array();
    } else {
        if ( !is_array( $headers ) ) {
            // Explode the headers out, so this function can take both
            // string headers and an array of headers.
            $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
        } else {
            $tempheaders = $headers;
        }
        $headers = array();
        $cc = array();
        $bcc = array();

        // If it's actually got contents
        if ( !empty( $tempheaders ) ) {
            // Iterate through the raw headers
            foreach ( (array) $tempheaders as $header ) {
                if ( strpos($header, ':') === false ) {
                    if ( false !== stripos( $header, 'boundary=' ) ) {
                        $parts = preg_split('/boundary=/i', trim( $header ) );
                        $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
                    }
                    continue;
                }
                // Explode them out
                list( $name, $content ) = explode( ':', trim( $header ), 2 );

                // Cleanup crew
                $name    = trim( $name    );
                $content = trim( $content );

                switch ( strtolower( $name ) ) {
                    // Mainly for legacy -- process a From: header if it's there
                    case 'from':
                        $bracket_pos = strpos( $content, '<' );
                        if ( $bracket_pos !== false ) {
                            // Text before the bracketed email is the "From" name.
                            if ( $bracket_pos > 0 ) {
                                $from_name = substr( $content, 0, $bracket_pos - 1 );
                                $from_name = str_replace( '"', '', $from_name );
                                $from_name = trim( $from_name );
                            }

                            $from_email = substr( $content, $bracket_pos + 1 );
                            $from_email = str_replace( '>', '', $from_email );
                            $from_email = trim( $from_email );

                        // Avoid setting an empty $from_email.
                        } elseif ( '' !== trim( $content ) ) {
                            $from_email = trim( $content );
                        }
                        break;
                    case 'content-type':
                        if ( is_array($message) ) {
                            // Multipart email, ignore the content-type header
                            break;
                        }
                        if ( strpos( $content, ';' ) !== false ) {
                            list( $type, $charset_content ) = explode( ';', $content );
                            $content_type = trim( $type );
                            if ( false !== stripos( $charset_content, 'charset=' ) ) {
                                $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
                            } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
                                $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
                                $charset = '';
                            }

                        // Avoid setting an empty $content_type.
                        } elseif ( '' !== trim( $content ) ) {
                            $content_type = trim( $content );
                        }
                        break;
                    case 'cc':
                        $cc = array_merge( (array) $cc, explode( ',', $content ) );
                        break;
                    case 'bcc':
                        $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
                        break;
                    default:
                        // Add it to our grand headers array
                        $headers[trim( $name )] = trim( $content );
                        break;
                }
            }
        }
    }

    // Empty out the values that may be set
    $phpmailer->ClearAllRecipients();
    $phpmailer->ClearAttachments();
    $phpmailer->ClearCustomHeaders();
    $phpmailer->ClearReplyTos();

    $phpmailer->Body= '';
    $phpmailer->AltBody= '';

    // From email and name
    // If we don't have a name from the input headers
    if ( !isset( $from_name ) )
        $from_name = 'WordPress';

    /* If we don't have an email from the input headers default to wordpress@$sitename
     * Some hosts will block outgoing mail from this address if it doesn't exist but
     * there's no easy alternative. Defaulting to admin_email might appear to be another
     * option but some hosts may refuse to relay mail from an unknown domain. See
     * https://core.trac.wordpress.org/ticket/5007.
     */

    if ( !isset( $from_email ) ) {
        // Get the site domain and get rid of www.
        $sitename = strtolower( $_SERVER['SERVER_NAME'] );
        if ( substr( $sitename, 0, 4 ) == 'www.' ) {
            $sitename = substr( $sitename, 4 );
        }

        $from_email = 'wordpress@' . $sitename;
    }

    /**
     * Filter the email address to send from.
     *
     * @since 2.2.0
     *
     * @param string $from_email Email address to send from.
     */
    $phpmailer->From = apply_filters( 'wp_mail_from', $from_email );

    /**
     * Filter the name to associate with the "from" email address.
     *
     * @since 2.3.0
     *
     * @param string $from_name Name associated with the "from" email address.
     */
    $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );

    // Set destination addresses
    if ( !is_array( $to ) )
        $to = explode( ',', $to );

    foreach ( (array) $to as $recipient ) {
        try {
            // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
            $recipient_name = '';
            if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
                if ( count( $matches ) == 3 ) {
                    $recipient_name = $matches[1];
                    $recipient = $matches[2];
                }
            }
            $phpmailer->AddAddress( $recipient, $recipient_name);
        } catch ( phpmailerException $e ) {
            continue;
        }
    }

    // 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 mail's subject and body
    $phpmailer->Subject = $subject;

    if ( is_string($message) ) {
        $phpmailer->Body = $message;

        // 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 );

        // For backwards compatibility, new multipart emails should use
        // the array style $message. This never really worked well anyway
        if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
            $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
    }
    elseif ( is_array($message) ) {
        foreach ($message as $type => $bodies) {
            foreach ((array) $bodies as $body) {
                if ($type === 'text/html') {
                    $phpmailer->Body = $body;
                }
                elseif ($type === 'text/plain') {
                    $phpmailer->AltBody = $body;
                }
                else {
                    $phpmailer->AddAttachment($body, '', 'base64', $type);
                }
            }
        }
    }

    // Add any CC and BCC recipients
    if ( !empty( $cc ) ) {
        foreach ( (array) $cc as $recipient ) {
            try {
                // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
                $recipient_name = '';
                if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
                    if ( count( $matches ) == 3 ) {
                        $recipient_name = $matches[1];
                        $recipient = $matches[2];
                    }
                }
                $phpmailer->AddCc( $recipient, $recipient_name );
            } catch ( phpmailerException $e ) {
                continue;
            }
        }
    }

    if ( !empty( $bcc ) ) {
        foreach ( (array) $bcc as $recipient) {
            try {
                // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
                $recipient_name = '';
                if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
                    if ( count( $matches ) == 3 ) {
                        $recipient_name = $matches[1];
                        $recipient = $matches[2];
                    }
                }
                $phpmailer->AddBcc( $recipient, $recipient_name );
            } catch ( phpmailerException $e ) {
                continue;
            }
        }
    }

    // Set to use PHP's mail()
    $phpmailer->IsMail();

    // Set custom headers
    if ( !empty( $headers ) ) {
        foreach ( (array) $headers as $name => $content ) {
            $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
        }
    }

    if ( !empty( $attachments ) ) {
        foreach ( $attachments as $attachment ) {
            try {
                $phpmailer->AddAttachment($attachment);
            } catch ( phpmailerException $e ) {
                continue;
            }
        }
    }

    /**
     * Fires after PHPMailer is initialized.
     *
     * @since 2.2.0
     *
     * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference.
     */
    do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );

    // Send!
    try {
        return $phpmailer->Send();
    } catch ( phpmailerException $e ) {
        return false;
    }
}

Öyleyse, örneğin "wp-content / mu-plugins / functions.php" dosyanızın içine koyarsanız WP sürümünü geçersiz kılar. Başlıklarla uğraşmadan hoş bir kullanımı vardır, örneğin:

// Set $to to an hotmail.com or outlook.com email
$to = "YourEmail@hotmail.com";

$subject = 'wp_mail testing multipart';

$message['text/plain'] = 'Hello world! This is plain text...';
$message['text/html'] = '<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

<p>Hello World! This is HTML...</p> 

</body>
</html>';

add_filter( 'wp_mail_from', $from_func = function ( $from_email ) { return 'foo@bar.com'; } );
add_filter( 'wp_mail_from_name', $from_name_func = function ( $from_name ) { return 'Foo'; } );

// send email
wp_mail( $to, $subject, $message );

remove_filter( 'wp_mail_from', $from_func );
remove_filter( 'wp_mail_from_name', $from_name_func );

Lütfen bunu gerçek e-postalarla test etmediğimi unutmayın ...


Eklentileri olması ve test kodunu çalıştırması için bunu ekledim; işe yaradı. Varsayılan çekirdek bildirimleri (yeni kullanıcı bildirimi vb.) Test ettim ve de çalıştı. Bu haftasonu testler yapmaya devam edeceğim ve her şey çalışırsa, eklentilerin bununla nasıl çalışacağını göreceğim. Özellikle mesajın ham verilerine bakacağım. Bu çok zaman alan bir görev olacak, ancak işin bitince tekrar rapor edeceğime emin olabilirsiniz. Wp_mail () 'in çalışmayacağı bir senaryo varsa (aksi halde olması gerektiği zaman), lütfen bana bildirin. Bu cevap için teşekkür ederim.
Christine Cooper

İyi şeyler, çıktıyı gözüme çarptım ve iyi görünüyor - aslında yama sadece wp_mail'i bir dizi geçmesi durumunda PHPMailer'in standart rock solid işlemesini kullanıyor ve aksi halde varsayılan olarak tehlikeli WP öğelerini kullanıyor (geriye dönük uyumluluk için) bu yüzden iyi olmalı (tabii ki burada şerefsizce kudos yama yazarlarına gider) ... Şu andan itibaren kullanacağım (ve sonunda retro-fitting) - ve her ikisini de html / plain kullandığınız için tekrar teşekkürler spam olarak
tarife

1
Olası tüm senaryolarda test ettik ve harika çalışıyor. Yarın bir bülten çekeceğiz ve kullanıcılardan herhangi bir şikayet alıp almadığımızı göreceğiz. Yapmamız gereken küçük değişiklikler, diziyi db'ye yerleştirilirken diziyi dezenfekte etmek / sterilize etmekti (db'de bir cronun küçük hacimlerde gönderdiği kuyruğunda mesajlar var). Bu sorunun farkına varabilmemiz için, bu soru ödül kazanana kadar açık ve beklemede kalmasına izin vereceğim. Umarım, bu yama veya bir alternatif çekirdeğe eklenecektir. Ya da daha önemlisi, neden olmasın? Ne düşünüyorlar?
Christine Cooper

Bağlantılı trac biletinde bir güncelleme yaptığını rastgele fark ettim. Bu, bu kod için bir güncelleme mi? Eğer öyleyse, cevabınızı güncel tutması için cevabınızı burada da düzenleyerek bu güncellemeyi gönderebilir misiniz? Çok teşekkür ederim.
Christine Cooper

Merhaba, hayır öyle, kod aynı ... tam olarak (onun umut bazı dikkatini çekmenin olarak) o çakışma olmadan birleştirir, böylece cari gövde karşı yama sadece bir yenileme oldu
bonger

4

Bu gerçekten hiç bir WordPress hata değildir, bu bir olduğunu phpmailersize bakarsak özel başlıklar için izin vermeyerek bir ... class-phpmailer.php:

public function getMailMIME()
{
    $result = '';
    $ismultipart = true;
    switch ($this->message_type) {
        case 'inline':
            $result .= $this->headerLine('Content-Type', 'multipart/related;');
            $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
            break;
        case 'attach':
        case 'inline_attach':
        case 'alt_attach':
        case 'alt_inline_attach':
            $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
            $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
            break;
        case 'alt':
        case 'alt_inline':
            $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
            $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
            break;
        default:
            // Catches case 'plain': and case '':
            $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
            $ismultipart = false;
            break;
    }

Sorunlu varsayılan durumu, karakter dizisi ve sınırsız olarak ekstra başlık satırının çıktısı olduğunu görebilirsiniz. İçerik türünü filtre ile ayarlamak, bunu kendi başına çözmez, çünkü altburada durum message_typekontrol tarafından AltBodybaşlatıldığından, içerik türü yerine boş değildir.

protected function setMessageType()
{
    $type = array();
    if ($this->alternativeExists()) {
        $type[] = 'alt';
    }
    if ($this->inlineImageExists()) {
        $type[] = 'inline';
    }
    if ($this->attachmentExists()) {
        $type[] = 'attach';
    }
    $this->message_type = implode('_', $type);
    if ($this->message_type == '') {
        $this->message_type = 'plain';
    }
}

public function alternativeExists()
{
    return !empty($this->AltBody);
}

Sonunda, bunun anlamı, bir dosya veya satır içi resim eklediğiniz anda veya AltBodyrahatsız edici hata atlanmalıdır. Ayrıca çünkü orada yakında olduğunca açık bir şekilde ayarlanabilir içerik türüne gerek olmadığı anlamına gelir AltBodyo ayarlandığında multipart/alternativetarafından phpmailer.

Yani basit cevap:

add_action('phpmailer_init','wp_mail_set_text_body');
function wp_mail_set_text_body($phpmailer) {
     if (empty($phpmailer->AltBody)) {$phpmailer->AltBody = strip_tags($phpmailer->Body);}
}

Öyleyse, başlıkları açıkça ayarlamanız gerekmez;

 $message ='<html>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 </head>
 <body>
     <p>Hello World! This is HTML...</p> 
 </body>
 </html>';

 wp_mail($to,$subject,$message);

Ne yazık ki, phpmailersınıftaki işlevlerin ve özelliklerin çoğu korunuyor, eğer bunun için geçerli bir alternatif göndermeden önce MIMEHeadersözelliği phpmailer_initkanca ile basitçe kontrol etmek ve geçersiz kılmak olacaktır .


2

Sadece bir eklenti yayınladı kullanıcılar şu anda WordPress ve Im oynamaya html şablonları kullanmasına izin dev sürümü basit bir metin yedeği ekleyin. Aşağıdakileri yaptım ve testlerimde yalnızca bir sınır eklendi ve e-postalar Hotmail’e para cezasına çarptı.

add_action( 'phpmailer_init', array($this->mailer, 'send_email' ) );

/**
* Modify php mailer body with final email
*
* @since 1.0.0
* @param object $phpmailer
*/
function send_email( $phpmailer ) {

    $message            =  $this->add_template( apply_filters( 'mailtpl/email_content', $phpmailer->Body ) );
    $phpmailer->AltBody =  $this->replace_placeholders( strip_tags($phpmailer->Body) );
    $phpmailer->Body    =  $this->replace_placeholders( $message );
}

Temelde burada yaptığım şey phpmailer nesnesini değiştirmek, mesajı bir html şablonuna yüklemek ve Body özelliğine ayarlamak. Ayrıca orijinal mesajı alıp AltBody özelliğini ayarladım.


2

Benim basit çözümüm html2text https://github.com/soundasleep/html2text 'i şu şekilde kullanmaktır:

add_action( 'phpmailer_init', 'phpmailer_init' );

//http://wordpress.stackexchange.com/a/191974
//http://stackoverflow.com/a/2564472
function phpmailer_init( $phpmailer )
{
  if( $phpmailer->ContentType == 'text/html' ) {
    $phpmailer->AltBody = Html2Text\Html2Text::convert( $phpmailer->Body );
  }
}

İşte https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 ayrıca bir öz hakkında.


2

Kendi 'AltBody'lerini eklemek için' phpmailer_init 'kancasını kullanan herkes için:

Alternatif metin gövdesi, el ile silinmediğiniz sürece arka arkaya gönderilen farklı postalar için tekrar kullanılır ! WordPress, bu özelliğin kullanılmasını beklememesi nedeniyle wp_mail () 'de temizlemez.

Bu, alıcıların potansiyel olarak onlar için olmayan postaları almasına neden olur. Neyse ki, HTML etkin posta istemcileri kullanan çoğu kişi metin sürümünü görmez, ancak bu temelde bir güvenlik sorunudur.

Neyse ki kolay bir düzeltme var. Bu altbody değiştirme bitini içerir; Html2Text PHP kütüphanesine ihtiyacınız olduğuna dikkat edin:

add_filter( 'wp_mail', 'wpse191923_force_phpmailer_reinit_for_multiple_mails', -1 );
function wpse191923_force_phpmailer_reinit_for_multiple_mails( $wp_mail_atts ) {
  global $phpmailer;

  if ( $phpmailer instanceof PHPMailer && $phpmailer->alternativeExists() ) {
    // AltBody property is set, so WordPress must already have used this
    // $phpmailer object just now to send mail, so let's
    // clear the AltBody property
    $phpmailer->AltBody = '';
  }

  // Return untouched atts
  return $wp_mail_atts;
}

add_action( 'phpmailer_init', 'wpse191923_phpmailer_init_altbody', 1000, 1 );
function wpse191923_phpmailer_init_altbody( $phpmailer ) {
  if ( ( $phpmailer->ContentType == 'text/html' ) && empty( $phpmailer->AltBody ) ) {
    if ( ! class_exists( 'Html2Text\Html2Text' ) ) {
      require_once( 'Html2Text.php' );
    }
    if ( ! class_exists( 'Html2Text\Html2TextException' ) ) {
      require_once( 'Html2TextException.php' );
    }
    $phpmailer->AltBody = Html2Text\Html2Text::convert( $phpmailer->Body );
  }
}

İşte bu sorunu çözmek için değiştirdiğim bir WP eklentisi için de bir özeti: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661

Ne yazık ki, yukarıda belirtilen kancayı kullanan diğer çözümler hakkında yorum yapamam, çünkü henüz yorum yapacak kadar bilgim yok.


1

bu, buradaki ilk gönderiye tam bir cevap olmayabilir, ancak burada bir alt yapı kurmaya ilişkin olarak sunulan çözümlerden bazılarına alternatif

temelde, bazı dönüşüm / striptag'lere güvenmek yerine, html kısmına ek olarak farklı bir altbody (yani düz metin) koymam gerekiyordu. bu yüzden işe yaramadı gibi geldi.

/* setting the message parts for wp_mail()*/
$markup = array();
$markup['html'] = '<html>some html</html>';
$markup['plaintext'] = 'some plaintext';
/* message we are sending */    
$message = maybe_serialize($markup);


/* setting alt body distinctly */
add_action('phpmailer_init', array($this, 'set_alt_mail_body'));

function set_alt_mail_body($phpmailer){
    if( $phpmailer->ContentType == 'text/html' ) {
        $body_parts = maybe_unserialize($phpmailer->Body);

        if(!empty($body_parts['html'])){
            $phpmailer->MsgHTML($body_parts['html']);
        }

        if(!empty($body_parts['plaintext'])){
            $phpmailer->AltBody = $body_parts['plaintext'];
        }
    }   
}

0

Wordpress çekirdeğinde herhangi bir kod çakışması oluşturmak istemiyorsanız, alternatif ya da en basit çözümün, phpmailer_initpostadaki fiili posta gönderiminden önce yapacakları eylem eklemek olduğunu düşünüyorum wp_mail. Açıklamamı basitleştirmek için aşağıdaki kod örneğine bakın:

<?php 

$to = '';
$subject = '';
$from = '';
$body = 'The text html content, <html>...';

$headers = "FROM: {$from}";

add_action( 'phpmailer_init', function ( $phpmailer ) {
    $phpmailer->AltBody = 'The text plain content of your original text html content.';
} );

wp_mail($to, $subject, $body, $headers);

PHPMailer sınıfı AltBodyözelliğine bir içerik eklerseniz , varsayılan içerik türü otomatik olarak ayarlanır multipart/alternative.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.