Skip to content

Improve handing of SMTP plugins that re-implement wp_mail #12632

@benbowler

Description

@benbowler

Bug Description

A user reported the HTML Email Report being delivered as plain text when an SMTP plugin that re-implements the wp_mail function is used. The replacement wp_mail bypasses the phpmailer_init action we rely on to set the multipart/alternative content type that tells email clients the message contains both a plain text and HTML body.

We should update the plugin so that, when wp_mail is replaced by an implementation that does not fire PHPMailer hooks, the email is still delivered with the correct HTML content type and renders correctly in the recipient's email client.

Steps to reproduce

Full details and screenshot here


Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • Email reports should continue to render correctly in the recipient's email client when the default WordPress email pipeline (PHPMailer) is in use, with both a plain text and HTML version delivered, as today.
  • Email reports should also render correctly when an alternative wp_mail implementation is in use that does not fire PHPMailer hooks. In this case the plain text alternative may be omitted, which is an acceptable compromise.

Implementation Brief

Files to modify

Backend

  • Update includes/Core/Email/Email.php:
    • In send_email_and_catch_errors(), inject a Content-Type: text/html; charset=UTF-8 entry into the $headers array passed to wp_mail() when no caller-supplied Content-Type is already present, so any wp_mail implementation that respects the headers argument treats the body as HTML.
    • Leave the existing phpmailer_init AltBody hook in place. When PHPMailer is the active mailer it will continue to upgrade the content type to multipart/alternative and attach the plain text alternate, preserving today's behaviour with no functional change for the default WordPress setup.
    • Add private helper headers_contain_content_type( array $headers ): bool for case-insensitive caller Content-Type detection so any caller-supplied content type is respected verbatim and not double-set.
    • Update @since tags on the touched methods accordingly.

Test Coverage

  • Update tests/phpunit/integration/Core/Email/EmailTest.php:
    • Cover that a Content-Type: text/html; charset=UTF-8 header is added to the wp_mail() call when no caller Content-Type is supplied.
    • Cover that a caller-supplied Content-Type header in any case is preserved verbatim and the default header is not added.
    • Cover that the phpmailer_init AltBody hook continues to set the plain text alternative when PHPMailer runs, so the existing multipart behaviour is not regressed.

QA Brief

  • Activate and configure Post SMTP to deliver via SMTP to an inspectable mailbox (Mailtrap, Mailpit, or a real inbox), and run its test send to confirm delivery works.
  • Trigger any Site Kit email send (e.g. an invitation via Site Kit → Admin Settings → Email Reporting, or a report via Tester Settings → Email Reporting), open the delivered email in the mailbox, and confirm the raw headers contain Content-Type: text/html; charset=UTF-8 with no multipart/alternative boundary and the body renders as styled HTML with no raw <html> or <table> markup visible.
  • Deactivate Post SMTP so the default WordPress wp_mail pipeline is active, trigger another Site Kit email send, and confirm the raw headers contain Content-Type: multipart/alternative with both text/plain and text/html parts and the HTML part still renders as styled HTML.
  • Repeat the Site Kit email send check under WP Mail SMTP in place of Post SMTP and confirm the same single-part text/html Content-Type and HTML rendering.
Before Image Image
After Image Image

Changelog entry

  • Fix bug that could cause plugins handling SMTP to send HTML emails as plaintext emails when sending Email reports.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Good First IssueGood first issue for new engineersP0High priorityTeam SIssues for Squad 1Type: EnhancementImprovement of an existing featureType: SupportSupport request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions