Set up DMARC and see who's sending email using your brand's domain.

Why we’re nuts about Mustachio

When  we launched Postmark Templates, I promised to share with you some of the thinking that went into building our own flavor of “Mustache,” which is called “Mustachio.”

Postmark Template Goals #

The Postmark team cares deeply about creating fantastic experiences for our customers. We put a lot of thought into each feature that we build, and balance many factors to make sure we focus our efforts on the aspects of our products that we think can provide the best outcomes for our users.

The Mustachio logo.

When we started planning the Templating experience, we had the following goals for the feature:

  1. An approachable experience that felt natural to developers and designers coming from multiple platforms.
  2. An editing experience that didn’t require many context switches between the template editing environment and an external code editor.
  3. A rock-solid, safe, Templating language with a good balance of power and simplicity.

To achieve these goals, we looked at a number of options including the Templating features provided by some of our competitors. After reviewing the options, the Mustache language felt like the best fit with what we wanted to accomplish.

Designing a Great Language #

Even if a person has never seen it before, templates written in Mustachio are immediately accessible. An author can accomplish a great deal with just a tiny bit of syntax:

{{ value }}

Knowing just this bit of syntax, one can start writing . However, In order to achieve the experience we were after, we needed to add two more features to the base language.

Model Inference #

If you’ve ever generated dynamic HTML, you’ve had to deal with weaving your dynamic data in with static elements. Depending on the language and tools you use, this can be a frustrating experience. One big factor for this frustration is the constant switching between markup, code, and browsers (a problem that is compounded when you create emails that have both Text and HTML bodies). We wanted to avoid the need to switch between editing environments when authoring templates; This requires a little bit of magic.

We extended Mustache to add something called “each” - a feature which is able to detect the dynamic content you’re using in your Template’s HTML, Text, and Subject, and to provide an example JSON model that you can use when integrating the Postmark Templates into your applications.

It is possible to loop over an array of values using basic Mustache:


However, for us to detect that ‘products’ is going to be used as a collection, we need a hint. We added the “each” keyword to Mustachio, which looks like this:

{{#each products}}{{product_name}}{{/each}}

Adding this tiny feature allows a template author to completely design an email in our editor, and then use the model we provide as a reference when leveraging the template in an application’s code. If your experience is anything like mine, this is a significantly streamlined process.

Adding Model Inference for our case was not a particularly difficult Engineering problem, but we think it is a powerful helper, and was missing from all of the templating languages we considered.

Complex Keys #

The second feature we added to Mustachio is called “Complex Keys.” Many derivatives of Mustache have support for complex keys, but here’s an example of the problem this feature solves (basic Mustache that will render a value 2 levels down):


And here’s the same thing in Mustachio:


This is a significant savings in markup, which makes the template easier to read.

In addition, we wanted to make sure you didn’t need to repeat elements of your data model, so we added a way to traverse “up” your model:

{{#each products}}
Thanks for your order of {{ . }} made on {{ ../order_date }}

Without the ability to traverse “up,” the model that would be required to make this same content  in Mustache ends up being pretty redundant (Note that the key for the 'product_name’ would also need to be changed from ’.’):

  products : [
      "product_name" : "ACME Rockets",
      "order_date": "8/27/2015"
      "product_name" : "ACME Rollerskates",
      "order_date": "8/27/2015"
      "product_name" : "ACME Parachutes",
      "order_date" : "8/27/2015"

Compared to the model required when using Mustachio:

  "order_date": “8/27/2015”,
  "products" : 
      "ACME Rockets",
      "ACME Rollerskates",
      "ACME Parachutes"

Adding just a little bit of syntax can save a lot of hair pulling!

What did we leave out? #

Now that I’ve discussed the features we added, let’s talk a little bit about what we left out. If you’re already familiar with Mustache, you’ll know that we did not include “partials” or “helpers” in our initial release of Postmark Templates.

There are two major reasons for this:

  1. The editing experience that supports partials is substantially harder to approach for users that are new to the feature, because they would need to understand a larger amount of internals on how templates are referenced and stored. Partials/helpers immediately demand more knowledge of how everything works, and a more complex UI to navigate between components of a template.
  2. The ability for users to manage changes in templates is harder, because changes to partials can significantly (and indirectly) alter the final appearance of content that is created from a template.

We know that some users will want to use partials to have greater code reuse, but we also know that many emails are “one off” and change infrequently. As we learn more about how our customers want to use the Postmark Templates feature, we plan on enhancing it accordingly.

Why didn't we use an existing project? #

There are many libraries out there that have already implemented Mustache. Each of these projects vary substantially in quality and scope. So, why wouldn’t we just fork one of those projects and make our changes? There are a few reasons we chose to build our own:

Mustachio provides features that enhance the Postmark Template experience. #

When appropriate, our team is perfectly satisfied with leveraging external, general-purpose, components. For example, our .net code relies upon extensively. In that case, the way an application does JSON Serialization is not the application’s differentiator, and it’s fairly simple to swap one serialization library for another.

If we were to use an “off-the-shelf” language for Postmark Templates, we would be “outsourcing” the implementation for a component that can make the Postmark Template experience awesome. We know that customers are concerned with lock-in, so we put a lot of thought into adding only a few key features, this makes converting templates to or from Mustachio an easy process, if a customer ever decides to use another Email Service Provider. We also made Mustachio Open Source, so that the templates can be leveraged in other applications.

Mustachio contains only the features we are prepared to support. #

In a perfect world, we’d all have every feature we could hope for. In the real world, we know that all features are a balance of many limited resources. If we selected an off-the-shelf component, we would need to be prepared to support many features, and the added complexity in our codebase. We would also need to be prepared to handle the latent bugs in an off-the-shelf solution, .

By constraining our language to the right feature set, we ensure that we can focus our energy on making sure those features are defect free.

Our product runs (mostly) on .net and Rails. #

Each of us is proficient in C# and one or two other languages. Limiting most of our development to a few target languages does a few things:

  1. Reduces operational complexity.
  2. Increases the “lottery factor.” (This is often called “bus factor,” but we’re positive people)
  3. Shares code “ownership” among the entire team.

We’re happy to leverage multiple tools/languages when there’s an obvious best-of-breed option. However, more consideration is required when those options do not match our skill sets; Anything that doesn’t run on the .net or Rails platforms need to overcome the drawbacks of added operational complexity, and the limitations on which team members can fix those components when they break.

Therefore, our ideal template language solution needed to be in written in .net or Ruby. Further, the Postmark backend is mostly .net, so offloading to a .net service is preferred to running an Ruby process.

All Hail Mustachio #

Software Engineering is a complex process that requires careful consideration for time, cost, and human factors. In our case, we knew that a great templating language was an invariant requirement of building and maintaining our new Templating API for years to come. We might have shortened development time by offloading the language work to an external library, but we felt that the investment in the core component of this feature set was justified.

All of the factors above led us to our solution of building a focused, C#, template parser. We think Mustachio is a great result, and we hope you can see the thought and effort that went into building it, when you use Postmark's transactional email templates

Andrew Theken

Andrew Theken

Dominator of board games, avid reader, and public library advocate.