Wp_mail () के माध्यम से मल्टीपार्ट (टेक्स्ट / html) ईमेल भेजने की संभावना है कि आपके डोमेन को प्रतिबंधित कर दिया जाएगा


37

सारांश

WP कोर में एक बग, भेजने की वजह से बहुखण्डीय के साथ ईमेल (html / पाठ) wp_mail () (स्पैम फ़ोल्डर में समाप्त ईमेल की संभावना को कम करने के लिए) होगा विडंबना यह है कि के साथ अपने डोमेन हॉटमेल (और अन्य माइक्रोसॉफ्ट ईमेल) द्वारा अवरुद्ध किया जा रहा होता है।

यह एक जटिल समस्या है जिसका उद्देश्य मैं किसी को एक व्यावहारिक समाधान खोजने में मदद करने के प्रयास में बहुत विस्तार से तोड़ सकता हूं जिसे अंततः कोर में लागू किया जा सकता है।

यह एक पुरस्कृत पाठ है। शुरू करते हैं...

बग

स्पैम फ़ोल्डरों में आपके न्यूज़लेटर के ईमेल समाप्त होने से बचने के लिए सबसे आम सलाह मल्टीपार्ट संदेश भेजना है।

मल्टी-पार्ट (माइम) एक ईमेल में एक ई-मेल संदेश के एक HTML और पाठ भाग दोनों को भेजने के लिए संदर्भित करता है। जब कोई क्लाइंट मल्टीपार्ट संदेश प्राप्त करता है, तो वह HTML संस्करण को स्वीकार कर सकता है यदि वह HTML को रेंडर कर सकता है, अन्यथा यह सादे पाठ संस्करण को प्रस्तुत करता है।

यह काम करने के लिए सिद्ध है। जब हम जीमेल पर भेजते हैं, हमारे सभी ईमेल स्पैम फोल्डर में तब तक उतरते हैं, जब तक कि हम मुख्य इनबॉक्स के माध्यम से आने पर संदेशों को मल्टीपार्ट करने के लिए नहीं बदलते। उत्तम सामग्री।

अब, जब wp_mail () के माध्यम से मल्टीपार्ट संदेश भेजते हैं, तो यह दो बार (यदि कस्टम रूप से सेट किया गया है) और एक बार बिना कंटेंट टाइप (मल्टीपार्ट / *) के दो बार आउटपुट करता है। इस व्यवहार के परिणामस्वरूप ईमेल को एक कच्चे संदेश के रूप में प्रदर्शित किया जाता है और कुछ ईमेलों पर मल्टीपार्ट नहीं किया जाता है, जिसमें सभी Microsoft (हॉटमेल, आउटलुक, आदि) शामिल हैं ...

Microsoft इस संदेश को रद्दी के रूप में चिह्नित करेगा, और कुछ संदेश जो प्राप्त करेगा, उसे प्राप्तकर्ता द्वारा मैन्युअल रूप से फ़्लैग किया जाएगा। दुर्भाग्य से , Microsoft ईमेल पते व्यापक रूप से उपयोग किए जाते हैं। हमारे 40% ग्राहक इसका उपयोग करते हैं।

इसकी पुष्टि Microsoft द्वारा हाल ही में हमारे द्वारा की गई ईमेल एक्सचेंज के माध्यम से की गई।

संदेशों को चिह्नित करने से डोमेन पूरी तरह से अवरुद्ध हो जाएगा । इसका मतलब यह है कि संदेश स्पैम फ़ोल्डर में नहीं भेजे जाएंगे , वे प्राप्तकर्ता को बिल्कुल भी वितरित नहीं किए जाएंगे

हमने अपना मुख्य डोमेन अब तक 3 बार अवरुद्ध किया है।

क्योंकि यह WP कोर में एक बग है, मल्टीपार्ट संदेश भेजने वाले प्रत्येक डोमेन को अवरुद्ध किया जा रहा है। समस्या यह है कि अधिकांश वेबमास्टरों को पता नहीं है कि क्यों। मैंने अपने शोध करते समय और अन्य उपयोगकर्ताओं को मंचों पर इस पर चर्चा करते हुए इसकी पुष्टि की है। इसके लिए कच्चे कोड में देरी करने और इस प्रकार के ईमेल संदेशों को काम करने का एक अच्छा ज्ञान होना आवश्यक है, जिन्हें हम अगले करने जा रहे हैं ...

इसे कोड में तोड़ देते हैं

हॉटमेल / आउटलुक अकाउंट बनाएं। फिर, निम्न कोड चलाएँ:

// 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 () स्क्रिप्ट है जो मल्टीपार्ट संदेश भेजेगा लेकिन कुछ और नहीं।

क्या करें

यहाँ उद्देश्य सामान्य wp_mail () फ़ंक्शन (कस्टम कस्टम मेलमेल फ़ंक्शन नहीं ) का उपयोग करके दोनों सामान्य (सादे पाठ) और मल्टीपार्ट संदेश भेजने का एक तरीका खोजना है ।

इसे हल करने का प्रयास करते समय, आपके सामने आने वाली मुख्य समस्या समय की मात्रा है जो आप डमी संदेश भेजने पर खर्च करेंगे, अगर वे प्राप्त करते हैं और मूल रूप से एस्पिरिन का एक बॉक्स खोल रहे हैं और Microsoft पर शाप दे रहे हैं क्योंकि आप उनके लिए उपयोग किए जाते हैं IE मुद्दों जबकि यहाँ gremlin दुर्भाग्य से वर्डप्रेस है।

अद्यतन करें

@Bonger द्वारा पोस्ट किया गया समाधान $messageसामग्री-प्रकार के वैकल्पिक विकल्पों से युक्त एक सरणी होने की अनुमति देता है। मैंने पुष्टि की है कि यह सभी परिदृश्यों में काम करता है।

हम इस सवाल को तब तक खुला रहने देंगे जब तक कि समस्या के बारे में जागरूकता बढ़ाने के लिए बाउंटी भाग न जाए, हो सकता है कि यह उस स्तर पर हो जहां इसे कोर में तय किया जाएगा। एक वैकल्पिक समाधान पोस्ट करने के लिए स्वतंत्र महसूस करें जहां $messageएक स्ट्रिंग हो सकती है।


1
जैसा कि wp_mail()फ़ंक्शन प्लग करने योग्य है, आपके प्रतिस्थापन को एक-उपयोग प्लगइन (wp-content / mu-plugins में) के रूप में परिभाषित नहीं कर रहा है, आपके लिए एक अच्छा समाधान नहीं है (और बाकी सब, कोर फिक्सिंग विफल)? किस मामले में सेटिंग के बाद मल्टीपार्ट / बाउंड्री चेक को स्थानांतरित नहीं किया जाएगा $phpmailer->ContentType = $content_type;(काम करने के बजाय) काम नहीं करेगा?
बोंगर

@bonger क्या आप कृपया अपने समाधान का विवरण देते हुए उत्तर लिख सकते हैं?
क्रिस्टीन कूपर

1
यो को कोर को संपादित करने की आवश्यकता नहीं है, क्योंकि wp_mailयह प्लग करने योग्य है । मूल फ़ंक्शन को एक प्लगइन में कॉपी करें, इसे संपादित करें जैसे आपको ज़रूरत है और प्लगइन को सक्रिय करें। वर्डप्रेस मूल के बजाय आपके संपादित फ़ंक्शन का उपयोग करेगा, जिसमें कोर को संपादित करने की कोई आवश्यकता नहीं है।
gmazzap

@ChristineCooper मैं ऐसा करने में संकोच करता हूं क्योंकि आप कहते हैं कि परीक्षण एक ऐसा शाही दर्द है, लेकिन पैच को देखते हुए। core.trac.wordpress.org/ticket/15448 ने @ rmccue / @ Mattybob द्वारा trac में सुझाव दिया है जो वास्तव में अच्छा तरीका है इसलिए मैं उस पर आधारित एक अप्रयुक्त उत्तर पोस्ट करूंगा ...
बोंगर

2
@ChristineCooper यदि आप phpmailer में साधारण हुक रखते हैं और $ phpmailer में टेक्स्ट बॉडी सेट करते हैं-> AltBody में वही त्रुटि होती है?
chifliiiii

जवाबों:


15

निम्नलिखित संस्करण के wp_mail()टिकट के साथ @ rmccue / @ MattyRob में लागू पैच के साथ है https://core.trac.wordpress.org/ticket/15448 , जो 4.2.2 के लिए रीफ़्रेश किया गया है, जो $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;
    }
}

इसलिए यदि आप इसे अपने जैसे "wp-content / mu-plugins / functions.php" फाइल में डालते हैं तो यह WP वर्जन को ओवरराइड कर देगा। यह हेडर के साथ किसी भी खिलवाड़ के बिना एक अच्छा उपयोग है, जैसे:

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

कृपया ध्यान दें कि मैंने वास्तविक ईमेल के साथ इसका परीक्षण नहीं किया है ...


मैंने इसे प्लगइन्स में जोड़ा है और परीक्षण कोड चलाया है; इसने काम कर दिया। मैंने डिफ़ॉल्ट कोर सूचनाओं (नए उपयोगकर्ता अधिसूचना आदि) का परीक्षण किया है और इसने काम भी किया है। मैं इस सप्ताह के अंत में परीक्षण करना जारी रखूंगा और देखूंगा कि प्लगइन्स कैसे काम करेंगे और मूल रूप से अगर सब कुछ काम करता है। मैं विशेष रूप से संदेश के कच्चे डेटा के माध्यम से देखूंगा। यह बहुत समय लेने वाला कार्य होगा लेकिन निश्चिंत रहें, जब काम होगा तब रिपोर्ट करूंगा। यदि कोई ऐसा परिदृश्य है जहाँ wp_mail () काम नहीं करेगा (जब उसे अन्यथा होना चाहिए), तो कृपया मुझे बताएँ। इस उत्तर के लिए धन्यवाद।
क्रिस्टीन कूपर

अच्छा सामान, मैंने आउटपुट को आंखों से देखा है और यह अच्छा लग रहा है - वास्तव में पैच सिर्फ wp_mail का उपयोग करता है एक सरणी पास करने के मामले में PHPMailer के मानक रॉक ठोस प्रसंस्करण का उपयोग करता है, और अन्यथा डोडी WP सामान के लिए चूक (पिछड़े संगतता के लिए) इसलिए यह अच्छा होना चाहिए (जाहिर है यहां कुडोस पैच लेखकों के पास जाता है) ... मैं अब से इसका उपयोग करने जा रहा हूं (और रेट्रो-फिटिंग अंततः) - और धन्यवाद के लिए वापस जानकारी का उपयोग करके दोनों html / सादा स्पैम के रूप में
टारगेट किए

1
हमने सभी संभावित परिदृश्यों में इसका परीक्षण किया है और यह बहुत अच्छा काम कर रहा है। हम कल एक समाचार पत्र निकालेंगे और हम देखेंगे कि क्या हमें उपयोगकर्ताओं से कोई शिकायत मिलती है। केवल मामूली बदलाव जो हमें करने की ज़रूरत थी, वह सरणी को पवित्र / अनिश्चित करना था जब इसे db में डाला जा रहा था (db में एक पंक्ति में संदेश हैं जहाँ एक क्रॉन इसे छोटे बल्बों में भेजता है)। मैं इस सवाल को तब तक खुला और लंबित रहने दूंगा जब तक कि इनाम खत्म न हो जाए ताकि हम इस मुद्दे पर जागरूकता ला सकें। उम्मीद है, यह पैच, या एक विकल्प कोर में जोड़ा जाएगा। या इससे भी महत्वपूर्ण बात, क्यों नहीं। वे क्या सोच रहे हैं!
क्रिस्टीन कूपर

मैंने अनियमित रूप से देखा कि आपने लिंक किए गए trac टिकट पर एक अपडेट किया। क्या यह इस कोड का अपडेट है? यदि ऐसा है, तो क्या आप कृपया अपने उत्तर को यहाँ संपादित करके इस अपडेट को पोस्ट कर सकते हैं ताकि यह उत्तर अपटूडेट रहे? आपका बहुत बहुत धन्यवाद।
क्रिस्टीन कूपर

हाय, नहीं, यह वर्तमान ट्रंक के खिलाफ पैच का सिर्फ एक रिफ्रेश था ताकि यह बिना किसी संघर्ष के विलीन हो जाए (कुछ ध्यान पाने की उम्मीद में), कोड बिल्कुल वैसा ही है ...
4

4

यह वास्तव में एक वर्डप्रेस बग नहीं है, यह phpmailerकस्टम हेडर की अनुमति नहीं देने में एक है ... यदि आप देखें 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;
    }

आप डिफेंडिंग डिफॉल्ट मामले को देख सकते हैं कि क्या अतिरिक्त हेडर लाइन को चारसेट के साथ आउटपुट किया गया है और कोई सीमा नहीं है। सामग्री प्रकार को फ़िल्टर द्वारा सेट करना केवल इससे ही हल नहीं होता है क्योंकि जाँच द्वारा altसेट किया message_typeगया मामला AltBodyसामग्री प्रकार के बजाय खाली नहीं है।

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

अंत में इसका मतलब यह है कि जैसे ही आप एक फ़ाइल या इनलाइन छवि संलग्न करते हैं, या सेट करते हैं AltBody, अपमानजनक बग को बायपास किया जाना चाहिए। इसका अर्थ यह भी है कि सामग्री प्रकार को स्पष्ट रूप से सेट करने की आवश्यकता नहीं है क्योंकि जैसे ही AltBodyयह सेट होता multipart/alternativeहै phpmailer

तो सरल उत्तर है:

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

फिर आपको हेडर को स्पष्ट रूप से सेट करने की आवश्यकता नहीं है, आप बस कर सकते हैं:

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

दुर्भाग्य से, phpmailerवर्ग में कई कार्यों और संपत्तियों की रक्षा की जाती है, यदि ऐसा नहीं है तो एक वैध विकल्प बस भेजने से पहले हुक के MIMEHeadersमाध्यम से संपत्ति की जांच करना और उसे ओवरराइड करना होगा phpmailer_init


2

मैंने अभी अभी एक प्लगइन जारी किया है ताकि उपयोगकर्ताओं को वर्डप्रेस और इम पर उपयोग करने के लिए एक सरल टेक्स्ट फॉलबैक जोड़ने के लिए देव संस्करण पर अभी खेल रहे हैं । मैंने निम्नलिखित किया और अपने परीक्षणों में मैंने केवल एक सीमा जोड़ी है और ईमेल हॉटमेल पर ठीक आ रहे हैं।

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

तो मूल रूप से मैं यहां क्या करता हूं, phpmailer ऑब्जेक्ट को संशोधित किया गया है, एक HTML टेम्पलेट के अंदर संदेश लोड करें और इसे बॉडी प्रॉपर्टी पर सेट करें। इसके अलावा, मैंने मूल संदेश लिया और AltBody संपत्ति सेट की।


2

इस तरह से html2text https://github.com/soundasleep/html2text का उपयोग करने का मेरा सरल उपाय है :

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

यहाँ https://gist.github.com/ewake/6c4d22cd856456480bd77b988b5c9e80 के बारे में भी जानकारी दी।


2

किसी के लिए भी 'phpmailer_init' हुक का उपयोग करने के लिए अपने 'AltBody' जोड़ने के लिए:

वैकल्पिक टेक्स्ट बॉडी को लगातार भेजे जाने वाले विभिन्न मेलों के लिए पुन: उपयोग किया जाता है , जब तक कि आप इसे मैन्युअल रूप से साफ़ नहीं करते हैं! वर्डप्रेस इसे wp_mail () में स्पष्ट नहीं करता है क्योंकि यह इस संपत्ति के उपयोग की उम्मीद नहीं करता है।

इसके परिणामस्वरूप प्राप्तकर्ताओं को संभावित रूप से मेल प्राप्त करना उनके लिए नहीं है। सौभाग्य से HTML- सक्षम मेल क्लाइंट का उपयोग करने वाले अधिकांश लोग टेक्स्ट संस्करण नहीं देखेंगे, लेकिन यह अभी भी मूल रूप से एक सुरक्षा समस्या है।

सौभाग्य से वहाँ एक आसान तय है। इसमें ऊंचाई प्रतिस्थापन बिट शामिल है; ध्यान दें कि आपको Html2Text PHP लाइब्रेरी की आवश्यकता है:

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

यहाँ इस समस्या को ठीक करने के लिए संशोधित एक WP प्लगइन के लिए एक जिन्न है: https://gist.github.com/youri--/c4618740b7c50c549314eaebc9f78661

दुर्भाग्य से, मैं अन्य समाधानों पर टिप्पणी नहीं कर सकता, जो कि पूर्वोक्त हुक का उपयोग करके, उन्हें इस बारे में चेतावनी देने के लिए, क्योंकि मेरे पास अभी तक टिप्पणी करने के लिए पर्याप्त प्रतिनिधि नहीं है।


1

यह यहाँ प्रारंभिक पोस्ट के लिए एक सटीक जवाब नहीं हो सकता है, लेकिन यह कुछ समाधानों के लिए एक वैकल्पिक विकल्प है जो एक संपूर्ण निकाय स्थापित करने से संबंधित है

अनिवार्य रूप से, मुझे कुछ रूपांतरण / स्ट्रिपटैग और व्हाट्सएप पर निर्भर होने के बजाय html के हिस्से में एक अलग altbody (यानी प्लेनटेक्स्ट) सेट करने की आवश्यकता थी। तो मैं इस के साथ आया था जो सिर्फ ठीक काम करने लगता है

/* 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

यदि आप वर्डप्रेस कोर में कोई कोड संघर्ष नहीं बनाना चाहते हैं, तो मुझे लगता है phpmailer_initकि मेल में वास्तविक भेजने से पहले कार्रवाई या वैकल्पिक समाधान को जोड़ना होगा wp_mail। मेरे स्पष्टीकरण को सरल बनाने के लिए नीचे दिया गया कोड उदाहरण देखें:

<?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 वर्ग की AltBodyसंपत्ति में एक सामग्री जोड़ते हैं तो डिफ़ॉल्ट सामग्री प्रकार स्वचालित रूप से सेट हो जाएगा multipart/alternative

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.