Email System

WordPress email architecture built on PHPMailer with extensive hook-based customization.

Source: wp-includes/pluggable.php, wp-includes/PHPMailer/, wp-includes/class-wp-phpmailer.php

Components

Component Description
class-wp-phpmailer.md WordPress PHPMailer extension with i18n
hooks.md All email-related actions and filters

Architecture

WordPress uses a bundled copy of PHPMailer (v7.x) in the PHPMailerPHPMailer namespace. The library is extended by WP_PHPMailer to provide WordPress-specific internationalization.

File Structure

wp-includes/
├── class-phpmailer.php        # Deprecated shim → PHPMailer/PHPMailer.php
├── class-smtp.php             # Deprecated shim → PHPMailer/SMTP.php  
├── class-pop3.php             # Standalone POP3 class (RFC 1939)
├── class-wp-phpmailer.php     # WordPress PHPMailer extension
└── PHPMailer/
    ├── PHPMailer.php          # Main PHPMailer class
    ├── SMTP.php               # SMTP transport class
    └── Exception.php          # PHPMailer exceptions

Deprecation Notes

Since WordPress 5.5.0:

  • class-phpmailer.php → Use PHPMailerPHPMailerPHPMailer directly
  • class-smtp.php → Use PHPMailerPHPMailerSMTP directly

Both legacy files create class aliases for backward compatibility.

wp_mail() Flow

The primary email function with extensive filtering at every stage.

wp_mail($to, $subject, $message, $headers, $attachments, $embeds)
    │
    ├── apply_filters('wp_mail')              # Filter all arguments
    │
    ├── apply_filters('pre_wp_mail')          # Short-circuit opportunity
    │   └── Return non-null to skip sending
    │
    ├── Instantiate WP_PHPMailer (if needed)
    │   └── Stored in global $phpmailer
    │
    ├── Parse headers (From, CC, BCC, Reply-To, Content-Type)
    │
    ├── Set From address
    │   ├── apply_filters('wp_mail_from')
    │   └── apply_filters('wp_mail_from_name')
    │
    ├── Add recipients (To, CC, BCC, Reply-To)
    │
    ├── Configure content
    │   ├── apply_filters('wp_mail_content_type')
    │   └── apply_filters('wp_mail_charset')
    │
    ├── Add attachments and embeds
    │   └── apply_filters('wp_mail_embed_args')
    │
    ├── do_action_ref_array('phpmailer_init', [&$phpmailer])
    │   └── Last chance to modify PHPMailer instance
    │
    └── $phpmailer->send()
        ├── Success: do_action('wp_mail_succeeded')
        └── Failure: do_action('wp_mail_failed')

Transport Methods

PHPMailer supports three transport methods, configured via $phpmailer->Mailer:

Method Property Description
mail isMail() PHP’s mail() function (default)
sendmail isSendmail() Direct sendmail binary
smtp isSMTP() SMTP server connection

WordPress defaults to mail. Switch to SMTP via phpmailer_init:

add_action( 'phpmailer_init', function( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.example.com';
    $phpmailer->SMTPAuth   = true;
    $phpmailer->Port       = 587;
    $phpmailer->Username   = '[email protected]';
    $phpmailer->Password   = 'secret';
    $phpmailer->SMTPSecure = PHPMailerPHPMailerPHPMailer::ENCRYPTION_STARTTLS;
});

Global Instance

WordPress maintains a single PHPMailer instance in global $phpmailer. This instance persists across multiple wp_mail() calls within a request.

The instance is cleared and reset at the start of each wp_mail() call:

  • clearAllRecipients()
  • clearAttachments()
  • clearCustomHeaders()
  • clearReplyTos()
  • Reset Body, AltBody, Encoding

Default From Address

When no From: header is provided:

  • Name: WordPress
  • Email: wordpress@{site_domain} (strips www. prefix)

Override via wp_mail_from and wp_mail_from_name filters.

Content Types

Type When Used
text/plain Default, no Content-Type header
text/html Content-Type header contains text/html
multipart/* When boundary is specified in headers

The text/html content type triggers $phpmailer->isHTML(true).

Embeds (Since 6.9.0)

The $embeds parameter allows inline image embedding:

wp_mail(
    '[email protected]',
    'Subject',
    '<img src="cid:logo">',
    ['Content-Type: text/html'],
    [],
    ['logo' => '/path/to/logo.png']
);

Error Handling

PHPMailer throws PHPMailerPHPMailerException on failures. WordPress catches these and fires wp_mail_failed with a WP_Error containing:

  • Exception message
  • Exception code
  • Original mail data (to, subject, message, headers, attachments, embeds)

Multisite Considerations

On multisite, fix_phpmailer_messageid() is hooked to phpmailer_init to set the hostname for Message-ID generation to the network domain.