SuperGeekery: A blog probably of interest only to nerds by John F Morton.

A blog prob­a­bly of inter­est only to nerds by John F Mor­ton.

The HTML email template in Craft CMS

Craft HTML email template option screenshot

The doc­u­men­ta­tion of Craft CMS improves con­stant­ly but for a CMS that evolves at the pace we’re used to with Craft, keep­ing up with doc­u­ment­ing every nook and cran­ny doesn’t always hap­pen. The HTML Email Tem­plate is pret­ty basic and has­n’t received much love in the docs yet.

Search­ing the Craft doc­u­men­ta­tion does­n’t turn up much infor­ma­tion. If you search the Craft Dis­cord com­mu­ni­ty, you’ll find doc­u­men­ta­tion nuggets scat­tered in con­ver­sa­tions. In this post, I’ll share what I know about using and cus­tomiz­ing the HTML email tem­plate in Craft. As with most of my posts, this is not just for you, but for future-me when I stum­ble upon this task again.

The doc­u­men­ta­tion of Craft CMS improves con­stant­ly but for a CMS that evolves at the pace we’re used to with Craft, keep­ing up with doc­u­ment­ing every nook and cran­ny doesn’t always hap­pen. The HTML Email Tem­plate is pret­ty basic and hasn’t received much love in the docs yet. 

Search­ing the Craft doc­u­men­ta­tion doesn’t turn up much infor­ma­tion. If you search the Craft Dis­cord com­mu­ni­ty, you’ll find doc­u­men­ta­tion nuggets scat­tered in con­ver­sa­tions. In this post, I’ll share what I know about using and cus­tomiz­ing the HTML email tem­plate in Craft. As with most of my posts, this is not just for you, but for future-me when I stum­ble upon this task again.


What is the HTML email template?

Craft needs to send trans­ac­tion­al emails to users and, by default, these emails are basic. Obvi­ous­ly, they are not designed to match the brand­ing of the site you’re build­ing. You can change this though by pro­vid­ing an HTML Email Tem­plate. You’ll find this option in the Set­tings > Email sec­tion of the Craft con­trol pan­el.

Like all tem­plates in Craft, the HTML email tem­plate is writ­ten in Twig. If you don’t pro­vide a cus­tom tem­plate, Craft CMS comes with a default built-in HTML email tem­plate, which you can see in the Github repos­i­to­ry in templates/_special/email.html’.

Here’s what that tem­plate con­tains.

What is the HTML email tem­plate? #

Craft needs to send trans­ac­tion­al emails to users and, by default, these emails are basic. Obvi­ous­ly, they are not designed to match the brand­ing of the site you’re build­ing. You can change this though by pro­vid­ing an HTML Email Tem­plate. You’ll find this option in the Set­tings > Email sec­tion of the Craft con­trol pan­el.

Like all tem­plates in Craft, the HTML email tem­plate is writ­ten in Twig. If you don’t pro­vide a cus­tom tem­plate, Craft CMS comes with a default built-in HTML email tem­plate, which you can see in the Github repos­i­to­ry in templates/_special/email.html’.

Here’s what that tem­plate con­tains.


<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 sin­gle vari­able, {{ body }}, passed into the tem­plate. Know­ing that you only need a body vari­able is like­ly enough infor­ma­tion to cus­tomize your emails for your needs. Slap a nice head­er logo on there and you’re set.

As you can see there is a sin­gle vari­able, {{ body }}, passed into the tem­plate. Know­ing that you only need a body vari­able is like­ly enough infor­ma­tion to cus­tomize your emails for your needs. Slap a nice head­er logo on there and you’re set.


Digging deeper

What oth­er vari­ables 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 avail­able. (Try to use the oth­ers, caused a ren­der­ing error in my tests. See the Debug­ging sec­tion below for some infor­ma­tion on that top­ic.)

If you keep dig­ging into the Craft source you’ll find val­ue you can expect emailKey to con­tain.

Craft has four pre­de­fined email keys: account_​activation, verify_​new_​email, forgot_​password, and test_​email.

In the tem­plate, we can test for those val­ues and ren­der ele­ments based on what we find. Since this is just Twig, you can use oth­er Twig vari­ables, like the date. Plu­g­ins can add addi­tion­al emailKey val­ues for you to test against. You’ll need to read the doc­u­men­ta­tion of the plu­g­ins you’re using that send emails to find out what to expect in those cas­es.

Here’s a valid HTML email sam­ple tem­plate show­ing you how you can use the con­di­tion­als.

Dig­ging deep­er #

What oth­er vari­ables 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 avail­able. (Try to use the oth­ers, caused a ren­der­ing error in my tests. See the Debug­ging sec­tion below for some infor­ma­tion on that top­ic.)

If you keep dig­ging into the Craft source you’ll find val­ue you can expect emailKey to con­tain.

Craft has four pre­de­fined email keys: account_​activation, verify_​new_​email, forgot_​password, and test_​email.

In the tem­plate, we can test for those val­ues and ren­der ele­ments based on what we find. Since this is just Twig, you can use oth­er Twig vari­ables, like the date. Plu­g­ins can add addi­tion­al emailKey val­ues for you to test against. You’ll need to read the doc­u­men­ta­tion of the plu­g­ins you’re using that send emails to find out what to expect in those cas­es.

Here’s a valid HTML email sam­ple tem­plate show­ing you how you can use the con­di­tion­als.


<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 cus­tomize wel­come email head­ers, for­got­ten pass­word head­ers, etc. You could also break this into sep­a­rate Twig files and include sub-tem­plates based on your con­di­tion­al state­ments.

<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 cus­tomize wel­come email head­ers, for­got­ten pass­word head­ers, etc. You could also break this into sep­a­rate Twig files and include sub-tem­­plates based on your con­di­tion­al state­ments.


Using MJML to create your template

HTML for emails is so cranky. I use MJML most of the time to gen­er­ate the HTML I need for email. You don’t need to install any­thing to build a basic tem­plate either, just go to the MJML Try It Live page. For exam­ple, here’s some starter MJML. Click the View HTML” but­ton in the upper-right-hand cor­ner and you’ll get valid HTML to paste into your HTML email tem­plate.

<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 cre­ate your tem­plate #

HTML for emails is so cranky. I use MJML most of the time to gen­er­ate the HTML I need for email. You don’t need to install any­thing to build a basic tem­plate either, just go to the MJML Try It Live page. For exam­ple, here’s some starter MJML. Click the View HTML” but­ton in the upper-right-hand cor­ner and you’ll get valid HTML to paste into your HTML email tem­plate. 

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

MJML code example
MJML render example

Example MJML


Customizing the content of the body of your email

What we’ve cov­ered so far lets you cus­tomize the frame sur­round­ing the body con­tent of the email being sent. Cus­tomiz­ing the body of the email is in a dif­fer­ent spot in the Craft con­trol pan­el. Go to the Util­i­ties > Sys­tem Mes­sage area and you change the text that will be gen­er­at­ed for the var­i­ous mes­sage types.

The default mes­sages start with Hey…” and I like to make that a bit more for­mal for the sites I build.

Cus­tomiz­ing the con­tent of the body of your email #

What we’ve cov­ered so far lets you cus­tomize the frame sur­round­ing the body con­tent of the email being sent. Cus­tomiz­ing the body of the email is in a dif­fer­ent spot in the Craft con­trol pan­el. Go to the Util­i­ties > Sys­tem Mes­sage area and you change the text that will be gen­er­at­ed for the var­i­ous mes­sage types.

The default mes­sages start with Hey…” and I like to make that a bit more for­mal for the sites I build.


Craft customize body of email

Debugging

If you’ve set your HTML Email Tem­plate and you’re not see­ing what you expect, you’ve prob­a­bly got an error in your Twig. If the sys­tem encoun­ters an error in your Twig, it will fall back to send­ing a plain text email and will dis­card your tem­plate that is throw­ing the error.

You’ll need to look into your logs to find out what’s going wrong. In your storage/logs direc­to­ry, look for Error ren­der­ing email tem­plate” in the web.log files. Here’s a link to the line in the source code show­ing where I found the text to look for.

In the screen­shot below, you’ll see I had an error in my email tem­plate when I tried to use replyEmail in my Twig code.

Debug­ging #

If you’ve set your HTML Email Tem­plate and you’re not see­ing what you expect, you’ve prob­a­bly got an error in your Twig. If the sys­tem encoun­ters an error in your Twig, it will fall back to send­ing a plain text email and will dis­card your tem­plate that is throw­ing the error.

You’ll need to look into your logs to find out what’s going wrong. In your storage/logs direc­to­ry, look for Error ren­der­ing email tem­plate” in the web.log files. Here’s a link to the line in the source code show­ing where I found the text to look for.

In the screen­shot below, you’ll see I had an error in my email tem­plate when I tried to use replyEmail in my Twig code.


Email Rendering Error in Craft logs

Email Rendering Error in Craft logs


Wrapping up

Are you inspired to up your email game in Craft? You can real­ly do quite a lot. For exam­ple, with what we’ve dis­cussed here, if some­one needs to reset their pass­word on a Mon­day, you could make that reset email include a ref­er­ence to how tough Mon­days are for every­one. Wel­come emails could be sea­son­al. If you come up with some­thing cool, let me know on Twit­ter. I’d love to hear about it. Good luck.

Wrap­ping up #

Are you inspired to up your email game in Craft? You can real­ly do quite a lot. For exam­ple, with what we’ve dis­cussed here, if some­one needs to reset their pass­word on a Mon­day, you could make that reset email include a ref­er­ence to how tough Mon­days are for every­one. Wel­come emails could be sea­son­al. If you come up with some­thing cool, let me know on Twit­ter. I’d love to hear about it. Good luck.