The HTML email template in Craft CMS
The documentation of Craft CMS improves constantly but for a CMS that evolves at the pace we’re used to with Craft, keeping up with documenting every nook and cranny doesn’t always happen. The HTML Email Template is pretty basic and hasn’t received much love in the docs yet.
Searching the Craft documentation doesn’t turn up much information. If you search the Craft Discord community, you’ll find documentation nuggets scattered in conversations. In this post, I’ll share what I know about using and customizing the HTML email template in Craft. As with most of my posts, this is not just for you, but for future-me when I stumble upon this task again.
The documentation of Craft CMS improves constantly but for a CMS that evolves at the pace we’re used to with Craft, keeping up with documenting every nook and cranny doesn’t always happen. The HTML Email Template is pretty basic and hasn’t received much love in the docs yet.
Searching the Craft documentation doesn’t turn up much information. If you search the Craft Discord community, you’ll find documentation nuggets scattered in conversations. In this post, I’ll share what I know about using and customizing the HTML email template in Craft. As with most of my posts, this is not just for you, but for future-me when I stumble upon this task again.
What is the HTML email template?
Craft needs to send transactional emails to users and, by default, these emails are basic. Obviously, they are not designed to match the branding of the site you’re building. You can change this though by providing an HTML Email Template. You’ll find this option in the Settings > Email section of the Craft control panel.
Like all templates in Craft, the HTML email template is written in Twig. If you don’t provide a custom template, Craft CMS comes with a default built-in HTML email template, which you can see in the Github repository in ‘templates/_special/email.html’.
Here’s what that template contains.
What is the HTML email template? #
Craft needs to send transactional emails to users and, by default, these emails are basic. Obviously, they are not designed to match the branding of the site you’re building. You can change this though by providing an HTML Email Template. You’ll find this option in the Settings > Email section of the Craft control panel.
Like all templates in Craft, the HTML email template is written in Twig. If you don’t provide a custom template, Craft CMS comes with a default built-in HTML email template, which you can see in the Github repository in ‘templates/_special/email.html’.
Here’s what that template contains.
<html>
<body>
<div style="max-width: 500px; font-size: 13px; line-height: 18px; font-family: HelveticaNeue, sans-serif;">
{{ body }}
</div>
</body>
</html>
<html>
<body>
<div style="max-width: 500px; font-size: 13px; line-height: 18px; font-family: HelveticaNeue, sans-serif;">
{{ body }}
</div>
</body>
</html>
As you can see there is a single variable, {{ body }}
, passed into the template. Knowing that you only need a body
variable is likely enough information to customize your emails for your needs. Slap a nice header logo on there and you’re set.
As you can see there is a single variable, {{ body }}
, passed into the template. Knowing that you only need a body
variable is likely enough information to customize your emails for your needs. Slap a nice header logo on there and you’re set.
Digging deeper
What other variables do we have access to besides body
? Let’s look into the Craft source code.
Check out this code block from the Mailer.php
file.
$variables = ($message->variables ?: []) + [
'emailKey' => $message->key,
'fromEmail' => Craft::parseEnv($settings->fromEmail),
'replyToEmail' => Craft::parseEnv($settings->replyToEmail),
'fromName' => Craft::parseEnv($settings->fromName),
];
Only the emailKey
key is available. (Try to use the others, caused a rendering error in my tests. See the Debugging section below for some information on that topic.)
If you keep digging into the Craft source you’ll find value you can expect emailKey
to contain.
Craft has four predefined email keys: account_activation, verify_new_email, forgot_password, and test_email.
In the template, we can test for those values and render elements based on what we find. Since this is just Twig, you can use other Twig variables, like the date. Plugins can add additional emailKey
values for you to test against. You’ll need to read the documentation of the plugins you’re using that send emails to find out what to expect in those cases.
Here’s a valid HTML email sample template showing you how you can use the conditionals.
Digging deeper #
What other variables do we have access to besides body
? Let’s look into the Craft source code.
Check out this code block from the Mailer.php
file.
$variables = ($message->variables ?: []) + [
'emailKey' => $message->key,
'fromEmail' => Craft::parseEnv($settings->fromEmail),
'replyToEmail' => Craft::parseEnv($settings->replyToEmail),
'fromName' => Craft::parseEnv($settings->fromName),
];
Only the emailKey
key is available. (Try to use the others, caused a rendering error in my tests. See the Debugging section below for some information on that topic.)
If you keep digging into the Craft source you’ll find value you can expect emailKey
to contain.
Craft has four predefined email keys: account_activation, verify_new_email, forgot_password, and test_email.
In the template, we can test for those values and render elements based on what we find. Since this is just Twig, you can use other Twig variables, like the date. Plugins can add additional emailKey
values for you to test against. You’ll need to read the documentation of the plugins you’re using that send emails to find out what to expect in those cases.
Here’s a valid HTML email sample template showing you how you can use the conditionals.
<html>
<body>
<div>This email was sent on {{ "now"|date("m/d/Y") }}.</div>
{% switch emailKey %}
{% case "account_activation" %}
<p>You're activating your email.</p>
{% case "verify_new_email" %}
<p>Let's verify your new email address</p>
{% case "forgot_password" %}
<p>Don't worry, we'll reset that password now.</p>
{% case "test_email" %}
<p>Testing makes perfect.</p>
{% default %}
<p>Unknown type of email. emailKey: {{emailKey}}</p>
{% endswitch %}
{{ body }}
</body>
</html>
Now you can customize welcome email headers, forgotten password headers, etc. You could also break this into separate Twig files and include sub-templates based on your conditional statements.
<html>
<body>
<div>This email was sent on {{ "now"|date("m/d/Y") }}.</div>
{% switch emailKey %}
{% case "account_activation" %}
<p>You're activating your email.</p>
{% case "verify_new_email" %}
<p>Let's verify your new email address</p>
{% case "forgot_password" %}
<p>Don't worry, we'll reset that password now.</p>
{% case "test_email" %}
<p>Testing makes perfect.</p>
{% default %}
<p>Unknown type of email. emailKey: {{emailKey}}</p>
{% endswitch %}
{{ body }}
</body>
</html>
Now you can customize welcome email headers, forgotten password headers, etc. You could also break this into separate Twig files and include sub-templates based on your conditional statements.
Using MJML to create your template
HTML for emails is so cranky. I use MJML most of the time to generate the HTML I need for email. You don’t need to install anything to build a basic template either, just go to the MJML Try It Live page. For example, here’s some starter MJML. Click the “View HTML” button in the upper-right-hand corner and you’ll get valid HTML to paste into your HTML email template.
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image width="250px" src="https://via.placeholder.com/500x150.png?text=LOGO"></mj-image>
<mj-divider border-color="#07d8ff"></mj-divider>
<mj-text font-size="20px" color="#2c2c2c" font-family="helvetica">{{ body }}</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Using MJML to create your template #
HTML for emails is so cranky. I use MJML most of the time to generate the HTML I need for email. You don’t need to install anything to build a basic template either, just go to the MJML Try It Live page. For example, here’s some starter MJML. Click the “View HTML” button in the upper-right-hand corner and you’ll get valid HTML to paste into your HTML email template.
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image width="250px" src="https://via.placeholder.com/500x150.png?text=LOGO"></mj-image>
<mj-divider border-color="#07d8ff"></mj-divider>
<mj-text font-size="20px" color="#2c2c2c" font-family="helvetica">{{ body }}</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Customizing the content of the body of your email
What we’ve covered so far lets you customize the frame surrounding the body content of the email being sent. Customizing the body of the email is in a different spot in the Craft control panel. Go to the Utilities > System Message area and you change the text that will be generated for the various message types.
The default messages start with “Hey…” and I like to make that a bit more formal for the sites I build.
Customizing the content of the body of your email #
What we’ve covered so far lets you customize the frame surrounding the body content of the email being sent. Customizing the body of the email is in a different spot in the Craft control panel. Go to the Utilities > System Message area and you change the text that will be generated for the various message types.
The default messages start with “Hey…” and I like to make that a bit more formal for the sites I build.
Debugging
If you’ve set your HTML Email Template and you’re not seeing what you expect, you’ve probably got an error in your Twig. If the system encounters an error in your Twig, it will fall back to sending a plain text email and will discard your template that is throwing the error.
You’ll need to look into your logs to find out what’s going wrong. In your storage/logs
directory, look for “Error rendering email template” in the web.log
files. Here’s a link to the line in the source code showing where I found the text to look for.
In the screenshot below, you’ll see I had an error in my email template when I tried to use replyEmail
in my Twig code.
Debugging #
If you’ve set your HTML Email Template and you’re not seeing what you expect, you’ve probably got an error in your Twig. If the system encounters an error in your Twig, it will fall back to sending a plain text email and will discard your template that is throwing the error.
You’ll need to look into your logs to find out what’s going wrong. In your storage/logs
directory, look for “Error rendering email template” in the web.log
files. Here’s a link to the line in the source code showing where I found the text to look for.
In the screenshot below, you’ll see I had an error in my email template when I tried to use replyEmail
in my Twig code.
Wrapping up
Are you inspired to up your email game in Craft? You can really do quite a lot. For example, with what we’ve discussed here, if someone needs to reset their password on a Monday, you could make that reset email include a reference to how tough Mondays are for everyone. Welcome emails could be seasonal. If you come up with something cool, let me know on Twitter. I’d love to hear about it. Good luck.
Wrapping up #
Are you inspired to up your email game in Craft? You can really do quite a lot. For example, with what we’ve discussed here, if someone needs to reset their password on a Monday, you could make that reset email include a reference to how tough Mondays are for everyone. Welcome emails could be seasonal. If you come up with something cool, let me know on Twitter. I’d love to hear about it. Good luck.