Brief, by Erica Steeves

Email is, without a doubt, one of the best tools we have to keep our users informed. For instance, both Nelio A/B Testing and Nelio Content use email notifications to let our users know when changes in their WordPress occur:

  • Nelio A/B Testing, for example, sends emails when a test has automatically ended letting the user know it’s no longer running and sharing relevant information about it, such as whether there was a winning variant.
  • Nelio Content keeps our users informed about the status of their blog. They’ll receive an email when they’ve been assigned a post, its status has changed, there are new editorial comments or tasks awaiting them, and so on.
Nelio Content Notification
Nelio Content Notification. This email, sent by Nelio Content, let me know that Toni marked a post as “pending” and that I was responsible of reviewing it.

Today we’ll talk about how you can send emails from WordPress and how to format them using HTML.

How to Send Emails from WordPress

To send emails from WordPress you need two things: on the one hand, you must configure your WordPress server following your hosting instructions and, on the other hand, you must learn to use the wp_mail function of WordPress.

As you can read in the WordPress documentation, wp_mail expects (at least) three parameters: the email recipient(s), its subject, and the message itself. For example, to send an email like the one I showed you in the previous screenshot, we would only need to implement a function similar to the following:

function send_email_on_status_change( $post, $old_status ) {
  $email = 'user@domain.com';
  $title = sprintf(
    __( 'Post status changed for "%s"', 'nelio' ),
    $post->post_title
  );
  $body = sprintf(
    __( 'Status was changed for post #%1$d "%2$s" by %3$s.', 'nelio' ),
    $post->ID,
    $post->post_title,
    wp_get_current_user()->display_name
  );
  // ...
  $body .= sprintf(
    __( "%1$s => %2$s", 'nelio' ),
    $old_status,
    $post->post_status
  );
  // ...
  wp_mail( $email, $title, $body );
}

The important thing here is to realize that any email sent from WordPress is, by default, plain text. An email formatted as text/plain might not be as fancy as its HTML counterpart, but it has a great benefit: you know for sure that the email will work in all existing email clients.

This is how we implemented Nelio Content’s emails, but what if you want to do something more beautiful?

Nelio A/B Testing

Native Tests for WordPress

Use your WordPress page editor to create variants and run powerful tests with just a few clicks. No coding skills required.

How to Use HTML in WordPress Emails

Well, that is precisely what we wanted to do with Nelio A/B Testing’s notifications. We wanted something elegant and colorful, and so we implemented an HTML template like this one:

Nelio A/B Testing Notification Email
Nelio A/B Testing notification email formatted using HTML.

which we then used on the emails generated and sent by Nelio A/B Testing.

If you want to send HTML-formatted emails, we need to tell WordPress so. The Content-Type header is used to determine how a certain email is formatted. By default, its value in WordPress is text/plain, but we can change it to text/html using the wp_mail_content_type filter:

function send_email_on_test_finish( $test ) {
  $email = 'user@domain.com';
  $title = sprintf(
    __( 'Test "%s" finished', 'nelio' ),
    $test->post_title
  );
  $body = '...';
  $content_type = function() { return 'text/html'; };
  add_filter( 'wp_mail_content_type', $content_type );
  wp_mail( $email, $title, $body );
  remove_filter( 'wp_mail_content_type', $content_type );
}

As you can see, you simply need to switch the Content-Type right before you send the email via wp_mail. Then, all you need to do is build the email’s copy using HTML tags… but, unfortunately, WordPress does not offer any standard mechanism for creating and using HTML templates, so it is entirely up to you to create one.

Assuming you have the template in a templates/email-template.php file with something like this:

<!DOCTYPE html PUBLIC "...">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
  <title><?php echo esc_html( $title ); ?></title>
  <style>...</style>
</head>
<body>
  <p><?php echo $html; ?></p>
  ...
</body>
</html>

you can use it like this:

function send_email_on_test_finish( $test ) {
  // ...
  $email = 'user@domain.com';
  $title = 'This is the title';
  $html  = 'This is the <strong>content!</strong>';
  ob_start();
  include './templates/template.php';
  $content = ob_get_clean();
  // ...
  wp_mail( $email, $title, $content );
}

Plugins to Create HTML Templates

As always, the WordPress ecosystem has numerous plugins that help you create HTML templates. A couple of examples are:

  • WordPress Email Template Designer. Create fully customizable responsive templates, with no coding required. It has many interesting features (such as real-time preview) and it’s under active development.
  • Email Templates. Pretty similar to the previous one. Choose the type of template you want, customize it, and enjoy!

If you want to create custom templates to use in your plugins, these plugins in particular aren’t exactly what you need, as they change all the appearance of all outgoing emails sent by WordPress. But they can obviously help you create the skeleton of your template, which you can then pack and integrate in the source code of your plugin.

I hope you liked this brief post and, if you did, share it with your friends. If there’s anything else we can do for you, let us know in the comments section below.

Featured image by Erica Steeves on Unsplash.

8 responses to “How to Format and Send HTML Emails in WordPress”

  1. Some dude Avatar
    Some dude

    This is pretty inaccurate. “wp_send_email()” isn’t even a function.

    Do this instead:

    function send_my_email() {
    $to = ‘example@example.com’;
    $subject = ‘The subject’;
    // GET EMAIL BODY FROM TEMPLATE
    $body = include get_template_directory().’/emails/test-email.php’;
    // SET HTML CONTENT TYPE
    $headers = array(‘Content-Type: text/html; charset=UTF-8’);
    // SEND WITH WP_MAIL() FUNCTION
    wp_mail($to, $subject, $body, $headers);
    }

    1. David Aguilera Avatar

      You’re absolutely right. In the last snippet I shared, I wrote wp_send_email instead of wp_mail – I don’t know what I was thinking, lol. Thanks for letting me know.

  2. Johannes Avatar
    Johannes

    Hey, thanks a lot for the post! How would I include the content within a WordPress Plugin?

    include with “./” or include plugin_dir_path(__FILE__) won’t work …

    What I want to do is to send multiple emails, while looping through a custom post-type. The body is pretty huge, so I am trying to store it in a separate file. All this is happening in a plugin.

    1. David Aguilera Avatar

      plugin_dir_path(__FILE__) is actually the way to go: it gives you the path of the directory that contains the “current file,” which you can then use to locate the file with your email template. Now, when you include the email template file, I assume you’ll want to assign it to a PHP $variable, right? If that’s the case, you need to use the following functions: ob_start(), include $file, and $var = ob_get_clean().

      Is this what you were missing, Johannes?

  3. Aaron Avatar
    Aaron

    Hi

    Very helpful thanks!

    When I reference the template file to render an html email all I get in the content is 1. Any idea what is missing?

    Thanks
    Aaron

    1. David Aguilera Avatar

      Hi, Aaron. Thanks for getting in touch. Indeed, there was an issue with our snippet. You can’t include the template directly into a variable. As you can read in its documentation, “include returns FALSE on failure and raises a warning. Successful includes, unless overridden by the included file, return 1.”

      So, how do you fix it? Well, I’ve changed the post itself but… essentially, you start a new output buffer with ob_start, include the file, and then read (and flush) the content of said buffer with ob_get_clean.

  4. daniel Avatar
    daniel

    Is there a filter to add html (e.g. header/footer) to every outgoing mail, that comes via wp_mail()?

    1. Antonio Villegas Avatar

      You can use this filter to modify the body of the email as you please.

Leave a Reply

Your email address will not be published. Required fields are marked *