PixelfearWeb Development by Jason Varga

Maintainable Emails with Stash and Postmaster

Tips, Workflow, ExpressionEngine

I’m sure we can all agree that HTML emails are a pain. This article will hopefully make them easier to deal with when using ExpressionEngine.

There are two parts to this solution. Objective HTML’s Postmaster and Mark Croxton’s Stash.


If you’ve been active in the EE community for any amount of time lately, you would have heard about Stash. There are a large number of articles on why it’s so great. If you haven’t heard of it, you should definitely check it out. A few articles to check out here, here and here.

For this article, we’re going to take advantage of Stash’s ability to use template inheritance.


This is a great add-on. It’ll allow us to keep all our email notifications in one centralized location. We can create our own custom email events (parcels) that get sent whenever we decide, using whatever templating we want.

For instance, you could send an email when a new entry is created. In channel x. And has a status of y. And the member was in group z. Whatever. It can also send emails through hooks. For example, when a CartThrob order has been completed. Cron jobs too. The list goes on.

Postmaster also has a built-in live template preview. You can select and entry, and as you type EE code, the template will be rendered. This is a killer feature and it’s what we’ll be taking advantage of for this technique.

The Problem

The painful part about HTML emails is that for the most part, code is stuck in the 90s. You need to use tables to get the best client support.
If you want to have a nicely designed email, as opposed to having plain text, you’ll need a lot of tables, trs, tds, presentational markup and inline styling. It’s ugly and hard to maintain.

You could have several emails on your site. Welcome emails, entry notifications, order confirmations, etc. That’s a lot of tables.

The Solution

To keep things as organized as we can, we’re going to throw as much of the ugly table code into one reusable wrapper template. We’ll keep that wherever you keep your Stash layouts. This template will have a the obvious parts: doctype, head, body; and then probably a wrapper table for the background, a sizing wrapper table, a header, content area, footer, etc.

So it might look something like this:

<!doctype html>
  <title>My Website</title> 
  <table width="100%">
      <td bgcolor="#CCC">    
        <table width="500" align="center" border="0" cellpadding="0" cellspacing="0" style="font-family: arial;">
          <tr><td bgcolor="#9e005d" style="color:white; font-size:20px; padding:20px"><b>My Website</b></td></tr>
            <td bgcolor="#FFF" style="color:#4d4d4d; font-size:14px; padding:20px;">

              <h2 style="font-size:20px;margin-bottom:30px;">[EMAIL TITLE]</h2>

              [EMAIL CONTENT]

              <p style="margin-bottom:0;color:#999;font-size:12px;">&mdash; My Website</p>

Ugly, right? This is a very simple example, too. You wouldn’t want to have to have that in every single email. Especially if it was more complicated.

The key points to note are where it says [EMAIL TITLE] and [EMAIL CONTENT]. These are the different pieces from email to email. We’ll get to that later.

To get the email to display the appropriate content, we’ll be doing the following:

  • Use a single stash embed inside Postmaster
  • Pass appropriate values into the embed
  • Insert content from the embed into the wrapper

Configuring Postmaster

Once you set up the parcel inside Postmaster - let’s say we’re sending a notification of a new entry - the template can just be a single Stash embed. We’ll pass in the required value(s).


This is saying to get my path_to_stash_templates/emails/new_entry file, and pass the entry’s title and channel to it. You could pass more if you want.

The Stash embed

The embed will be processing the content you pass to it, and it’ll drop it inside our email wrapper.

{!-- Our email wrapper --}

{!-- Set values to be passed into wrapper --}
  {stash:email_title}A new entry has been posted{/stash:email_title}
    <p>A new entry has been posted.</p>
      Title: {stash:title}<br />
      Channel: {stash:channel}

Again, this is very simple. If you want, instead of passing multiple values to the embed from Postmaster, you could just pass the entry_id and have complete control in this embed using an {exp:channel:entries} tag.

Back to the wrapper

In our embed above, we’ve stashed email_title and email_content.
We’ll need to be able to put that into the wrapper. To do that, just replace [EMAIL TITLE] and [EMAIL CONTENT] with {exp:stash:email_title} and {exp:stash:email_content} respectively.

There you have it

Postmaster is great, and it’s live templating is awesome, but devs tend to like having their templates saved as files. Now you can. With just the single Stash tag in Postmaster, you can leave your templates as files and it’ll be business as usual. You can do anything you would with Stash, here in Postmaster.

As you make changes in your Stash templates, you can come back to Postmaster and refresh the live preview. It’ll show you the complete rendered template.

Of course, your mileage may vary with how you want to structure your templates, but the processs would be the same.

Many thanks to @croxton and @objectivehtml for their add-ons.


blog comments powered by Disqus