[wp-trac] [WordPress Trac] #38102: Email header Content-Type: multipart boundary ignored by wp_mail

WordPress Trac noreply at wordpress.org
Tue Sep 20 07:29:16 UTC 2016


#38102: Email header Content-Type: multipart boundary ignored by wp_mail
--------------------------+-----------------------------
 Reporter:  drtonyb       |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Mail          |    Version:  4.6
 Severity:  normal        |   Keywords:
  Focuses:                |
--------------------------+-----------------------------
 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
 <?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 at 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
 <?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

--
Ticket URL: <https://core.trac.wordpress.org/ticket/38102>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list