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.

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?
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:

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.
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);
}
You’re absolutely right. In the last snippet I shared, I wrote
wp_send_email
instead ofwp_mail
– I don’t know what I was thinking, lol. Thanks for letting me know.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.
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 youinclude
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?
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
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
returnsFALSE
on failure and raises a warning. Successful includes, unless overridden by the included file, return1
.”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 withob_get_clean
.