Handlebars for templates and dynamic content

In November we quietly rolled out a new template language using Handlebars to support more complex dynamic content and templates. Since a full email strategy often involves different people—from developers to marketing to content editors (and more)—templates help separate data about an order, for example, from the formatting and style of the email. Handlebars gives your entire team more control and flexibility, including support for iterating over a collection (loops) and conditional data.

If you want to start using Handlebars right away, check out our documentation to see what's supported, or skip ahead to examples. If you're interested in learning about why we added a new template language and our process for releasing it (including why we didn't announce it from the start), read on.

Why a new template language?

When we launched Mandrill, you could say we weren't exactly sure who our customers would be. After all, we broke away from MailChimp to focus all of our energy on building a brand new product. We knew who MailChimp's customers were, and we had some ideas of where Mandrill would fall in the email world, but some of that was just educated guesses (as these things usually are). We were sure there would be some overlap between our customers and MailChimp's—we just had no idea exactly how much. And since we initially targeted MailChimp customers, we provided template support using a hopefully-familiar templating language from MailChimp. Shortly after, we added support for merge tags too, based on our customers' feedback.

We knew we wanted to add more template functionality eventually, but we heard over and over from users unaccustomed to MailChimp that the language wasn't familiar, and just didn't have all of the features or functionality they were hoping for. Since the MailChimp template language was designed and built around the WYSIWYG editor experience (and its limitations), instead of adapting it to suit Mandrill we decided to take a step back and decide how we would build template support from an API-first perspective. Handlebars was a common choice among developers we talked to, with familiar-enough syntax and examples to help people get up and going without much interference.

Development and testing

We have a lot of monitoring and tests in place for various parts of the application, but we often pay special attention to the code that's in the sending path for mail going through our system. Even seemingly-small changes, when compounded with the hundreds of millions of emails we process on a daily basis can have dramatic impacts on performance, load, and what users are expecting in the content of their emails. So we set out with a pretty comprehensive plan for implementing and testing a new merge language to ensure that the rollout would be seamless for our users.

As soon as the basic Handlebars functionality was ready, we built a converter that would work in the background to convert any existing merge tags or template content to the Handlebars context. For several weeks, a small sample of content being sent was put through the new converter (without actually changing what we sent) to confirm that the output was consistent with the existing template parser. This phase of testing also included load testing to make sure that we weren't increasing the processing time for individual messages in a way that could degrade performance once used in production-level loads.

Test converter flow

For any users wanting to try Handlebars, the option has been available in their Sending Defaults, as an API parameter, or using a custom SMTP header.

The converter we built is currently being used when a user has Handlebars selected as the default merge language in their Sending Defaults and pushes a template from MailChimp. We'll also be looking at ways to let you to manually convert mc:edit regions and merge tags to Handlebars if you want to take advantage of some of the expanded options available in Handlebars that aren't available with the MailChimp template language and merge tags.


Now that you know the backstory, let's look at some of the things you can do with Handlebars. We're adding more examples to our Knowledge Base soon, and you can check out the Handlebars documentation for more information now.

The basics

If you're familiar with MailChimp merge tags or simple merging of individual values, Handlebars works in much the same way.

Here's an example that might appear in your HTML or text content:

Hey {{firstName}}, thanks for ordering a wonderful selection of our nesting dolls.

To provide a value for your company name, pass the data in the global_merge_tags API parameter:

"global_merge_vars": [
            "name": "CompanyName",
            "content": "Nesting Doll Emporium"


<h1>Nesting Doll Emporium</h1>

To provide recipient-specific information, you'd use the merge_vars parameter:

"merge_vars": [
        "rcpt": "john@example.com",
        "vars": [
                "name": "firstName",
                "content": "John"
        "rcpt": "mary@example.com",
        "vars": [
                "name": "firstName",
                "content": "Mary"

John would get Hey John, thanks for ordering a wonderful selection of our nesting dolls., while Mary would receive an email with her name in the greeting: Hey Mary, thanks for ordering a wonderful selection of our nesting dolls..

Using loops

Lots of developers asked us for the ability to loop through an array to better format emails with a variable number of items in a table, for example. Let's say you want to include a number of different pieces of information about each product a customer purchased. Rather than have to render that on your side before sending, or have to know how many products you've sold at the time of template creation, loops let you set up a standard schema for displaying product information. Below is some HTML that's designed to format an image, name, quantity, price, sku, and description for each product.


   {{#each products}}
   <tr class="item">
        <td valign="top" class="textContent">
            <img src="{{img}}" width="50" height="75" class="itemImage" />
            <h4 class="itemName">{{name}}</h4>
            <span class="contentSecondary">Qty: {{qty}} x ${{price}}/each</span><br />
            <span class="contentSecondary sku"><em>{{sku}}</em></span><br />
            <span class="contentSecondary itemDescription">{{description}}</span>
        <td valign="top" class="textContent alignRight priceWidth">
<!-- // END PRODUCT LOOP -->

You'll see above that there are CSS classes applied to different product characteristics. With the merge tag language, since you couldn't iterate through a list of items, that CSS would've needed to be stored and passed in the API call instead of in the template to be sure it was applied for each product. With Handlebars, your template can hold all of that CSS information, and you only need to pass the actual data about each product.

If you have two products, you can pass those in your API call as an array, like this:

    "name": "products",
    "content": [
            "img": "http://kbcdn.mandrill.com/nesting-penguin.png",
            "qty": 2,
            "sku": "PENG001",
            "name": "Penguin",
            "description": "Solid wood, hand-painted penguin nesting doll with 5 different sizes included. Limited Edition.",
            "price": "12.99",
            "ordPrice": "25.98"
            "img": "http://kbcdn.mandrill.com/nesting-bear.png",
            "qty": 3,
            "sku": "BBEAR001",
            "name": "Brown bear",
            "description": "Solid wood, hand-painted brown bear nesting doll. Coordinates with our entire Bear collection. Includes 6 nested sizes.",
            "price": "12.99",
            "ordPrice": "38.97"

The above will render the product table with two products formatted similarly.

For a complete example using Handlebars, and to tie this all together, you can download an example receipt template and sample JSON API call (with placeholders for API key and recipient info) to see some of the Handlebars functionality in action. Here's a glimpse of the template and content:

Sent email using Handlebars example template

This is a fairly straightforward example using Handlebars, but we'd love to hear what you come up with!