wp_mail() is a core function of WordPress widely used by plugins to send emails. WordPress wraps inside that function a set of checks and normalization of data and finally uses the PHP Mailer library to actually send the message.

Acting on the different hooks available is possible to change the behavior of wp_mail() from just replacing the “from” name to using an external SMTP service.

Let’s start to analyze which hooks we can play with and a few ideas on how to use them creatively.

The first filter “wp_mail”

The first available filter is named “wp_mail” and is fired as soon as wp_mail() is invoked. It receives as input an associative array with keys:

  • to
  • subject
  • message
  • headers
  • attachments

The filter is invoked this way:

$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );

where the names in the compact() function are the names of the wp_mail() parameters.

For example, if you need to change the subject:

add_filter('wp_mail', 'my_wp_mail');

function my_wp_mail($atts) {
$atts['subject'] .= ' - Site Name';
return $atts;
}

Note: you should check for the existence of the key you’re changing since other plugins can remove it (they shouldn’t) and check the type of variable: headers and attachments can be both strings or arrays.

The wp_mail_from filter

This filter gives you access to the email address used as “From” address for your messages. WordPress creates a default address which is wordpress@yourdomain.tld which is not always the best to use especially if that mailbox doesn’t exist (neither as a redirect to another mailbox).

add_filter('wp_mail_from', 'my_wp_mail_from');

function my_wp_mail_from($email) {
return 'stefano@yourdomain.tld';
}

The wp_mail_from_name filter

This filter lets’ change the name of the sender. WordPress defaults it to… WordPress. It would be much better if you changed it to your name or blog title.

add_filter('wp_mail_from_name', 'my_wp_mail_from_name');

function my_wp_mail_from($name) {
return get_option('sitename');
}

Note: the option should be decoded removing the HTML entities.

The wp_mail_content_type and wp_mail_charset filter

This special filter enables to change of the content type of the message from plain text to HTML, for example. The content type, if not passed on using the headers parameter is preset by WordPress at “text/plain”.

A rich email using HTML to format the content should be text/html. It is important to link the content type to a charset. WordPress sets the charset to the blog one (which is now standardized to UTF-8). You can filter the charset using the wp_mail_charset hook.

If you want to send an HTML email with wp_mail() you should not intercept those hooks. You need only to create an HTML message, which is just a string, and mail it using wp_mail() passing on the header “Content-Type: text/html;charset=UTF-8“.

WordPress is smart enough to detect it and configure the mail session accordingly.

The last hook phpmailer_init

When everything is done, and the PHPMailer object used to send emails is ready, you have the chance to change it completely. The phpmailer_init hook is fired in this way:

do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );

hence you receive a reference to the object and not only you can change the object values or call the object methods, but you can change the object entirely.

To make a simple example, we want to add a reply to address to all outgoing messages:

add_action('phpmailer_init', 'my_phpmailer_init');

function my_phpmailer_init($mailer) {
$mailer->addReplyTo('stefano@mydomain.tld');
}

The error tracking with wp_mail_failed

If the mailing process fails, you can be notified by attaching to the event wp_mail_failed. As per WordPress standards, the action receives a WP_Error object with some error detail. You could use it to log mailing error events:

add_action('wp_mail_failed', 'my_wp_mail_failed');

function my_wp_mail_failed($error) {
file_put_content([ a filename ], $error->get_error_message() . "\n");
}

Similar Posts

Leave a Reply