[wp-trac] [WordPress Trac] #15448: wp_mail() sets Content-Type header twice for multipart emails

WordPress Trac noreply at wordpress.org
Wed Jun 25 23:19:39 UTC 2025


#15448: wp_mail() sets Content-Type header twice for multipart emails
-------------------------------------------------+-------------------------
 Reporter:  rmccue                               |       Owner:
                                                 |  SergeyBiryukov
     Type:  feature request                      |      Status:  reviewing
 Priority:  normal                               |   Milestone:  Future
                                                 |  Release
Component:  Mail                                 |     Version:
 Severity:  normal                               |  Resolution:
 Keywords:  has-patch has-unit-tests has-test-   |     Focuses:
  info                                           |
-------------------------------------------------+-------------------------

Comment (by rmccue):

 > True is, that there is no multiparted received mail as reported: it's
 just a regular plain text email.

 It's actually a broken multipart email, missing the boundary in the
 header. Note the Content-Type in your code:
 {{{
 Content-Type: multipart/alternative; charset=
 }}}

 Meanwhile, the body contains the multiple parts; your boundary is
 `----=_Part_18243133_1346573420.1408991447668`.

 This is the initial content-type header added by `$phpmailer->ContentType`
 here: https://github.com/WordPress/wordpress-
 develop/blob/6ea383f14783604934af91c60fee9471a40974df/src/wp-
 includes/pluggable.php#L483

 The ''correct'' header is attempted to be added within the headers check:
 https://github.com/WordPress/wordpress-
 develop/blob/6ea383f14783604934af91c60fee9471a40974df/src/wp-
 includes/pluggable.php#L517-L519

 Note that due to the `if ( ! empty( $headers ) )` guard around it, this
 will only be triggered if ''another'' header is added, and one which
 doesn't have special handling (from, content-type, cc, bcc, reply-to). The
 example code on the linked SE thread should do that via the MIME-Version
 header, but maybe it's not triggering properly. (You may also need to test
 with a "real" sendmail rather than MailHog.)

 In any case, it's arguable whether this is a core bug or phpmailer (WP's
 the one setting the content-type incorrectly and adding an extra header),
 but either way the functionality is broken :)

 If it's helpful, a simplified example might be:
 {{{
 $body = '--TestBoundary
 Content-Type: text/plain; charset=UTF-8

 This is a test email body.
 --TestBoundary
 Content-Type: text/html; charset=UTF-8
 <html><body>This is a test email body.</body></html>
 --TestBoundary--
 ';
 $headers = [
         'Example-Custom: value',
         'Content-Type: multipart/alternative; boundary="TestBoundary"',
 ];

 wp_mail( 'test at example.com', 'Test', $body, $headers );
 }}}


 Note that this patch goes beyond just fixing that bug to actually
 introduce multipart handling as a core capability.

 Aside: We're now so far down the track with this function as a pluggable
 one that retrofitting the ecosystem is going to be difficult. At the time
 I wrote the ticket, WP's market share was closer to 10% and there were
 many fewer drop-in replacements for `wp_mail()`. At this point it might be
 worth considering a new `wp_mail_multi()` instead.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/15448#comment:70>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list