[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