WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 7 months ago

#38102 new defect (bug)

Email header Content-Type: multipart boundary ignored by wp_mail

Reported by: drtonyb Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.6
Component: Mail Keywords:
Focuses: Cc:
PR Number:

Description

I have a requirement to send a multipart email with a csv attachment via wp_mail. The code I am using worked prior to upgrading to Wordpress 4.6. Following the upgrade, emails sent by my code appear to have no content when received. Examining the email source shows that both the content and attachment are present, but the header field Content-Type: multipart/mixed; boundary=... is missing, so the email client can't determine the content.

Here is a simplified example of code that sends a multipart (text and html) email demonstrating the problem:

<?php
        $multipart_boundary = 'frontier';

        $headers = array(
                "From: $from",
                "Reply-To: $from",
                "Content-Type: multipart/alternative; boundary=\"$multipart_boundary\""
        );

        $body = "--$multipart_boundary\r\n"
                . "Content-Type: text/plain; charset=ISO-8859-1; format=flowed\r\n"
                . "Content-Transfer-Encoding: 7bit\r\n"
                . "\r\n"
                . "This is not a red paragrph\r\n"
                . "--$multipart_boundary\r\n"
                . "Content-Type: text/html charset=utf-8\r\n"
                . "Content-Transfer-Encoding: 8bit\r\n"
                . "\r\n"
                . "<!DOCTYPE html>\r\n"
                . "<html>\r\n"
                . "<head>\r\n"
                . "<meta charset=\"utf-8\" />\r\n"
                . "<style>\r\n"
                . "p {color:#ff0000;}\r\n"
                . "</style>\r\n"
                . "</head>\r\n"
                . "<body>\r\n"
                . "<p>This is a red paragraph</p>\r\n"
                . "</body>\r\n"
                . "</html>\r\n"
                . "--$multipart_boundary--";

        wp_mail( 'whoever@example.com', 'Multipart email test', $body, $headers );

The email sent by this code should show either the text part or the html part, depending on the email client. I use Thunderbird and it shows no content at all.

The source of the problem is in the Wordpress file /includes/pluggable.php, function wp_mail().

The function argument $headers array/string supplied by the user is assigned to a variable $tempheaders and then $headers is set to an empty array. $tempheaders is then processed in a switch statement block starting at line 251 to extract the header fields From, Content_Type, Cc, Bcc and Reply-To. Any other header fields are considered 'custom headers' and are added back into the $headers array by the default case of the switch block. At the end of processing $tempheaders, if there are no 'custom header' fields present, then the $headers variable remains an empty array.

At line 441, the $headers variable is tested to see if any 'custom headers' need setting.

<?php
        // 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 ) );
        }

Strangely, not only does this if statement block set the 'custom headers' ($headers) when they exist, it also sets the Content-Type: multipart/...; boundary=... Hence, if $headers is empty, as is the case for my example above, the multipart boundary is not set.

The question is: why is setting the multipart boundary dependent on there being these so called 'custom headers'?

I have only noticed this problem since Wordpress 4.6+. Since version 4.6, the header field Reply-To was added to Wordpress' list of 'non-custom headers'. Prior to version 4.6, Reply-To was considered a 'custom header' and so, $headers was not empty and my code worked.

As a work-around, if I add Return-Path: ... to my headers, then everything works and my emails are readable again. However, I shouldn't need to do this.

I think this problem needs some serious attention.

Tony

Change History (0)

Note: See TracTickets for help on using tickets.