Change the wp_mail() behavior using the hooks

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 use an external SMTP service.

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

The first filter “wp_mail”

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

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

For example, if you need to change the subject:

1

2

3

4

5

6

add_filter('wp_mail','my_wp_mail');

functionmy_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 youre messages. WordPress creates a default address which is wordpress@yourdomain.tld which is not always the best to use specially if that mailbox doesn’t exists (neither as redirect to another mailbox).

1

2

3

4

5

add_filter('wp_mail_from','my_wp_mail_from');

functionmy_wp_mail_from($email){

return'stefano@yourdomain.tld';

}

The wp_mail_from_name filter

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

1

2

3

4

5

add_filter('wp_mail_from_name','my_wp_mail_from_name');

functionmy_wp_mail_from($name){

returnget_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 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, an 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:

1

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:

1

2

3

4

5

add_action('phpmailer_init','my_phpmailer_init');

functionmy_phpmailer_init($mailer){

$mailer->addReplyTo('stefano@mydomain.tld');

}

The error tracking with wp_mail_failed

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

1

2

3

4

5

add_action('wp_mail_failed','my_wp_mail_failed');

functionmy_wp_mail_failed($error){

file_put_content([afilename],$error->get_error_message()."\n");

}

My excuses for my bad english but it's the only way I have to communicate with you. Would you suggest
a correction? Leave a comment, thank you!