Using Handlebars for Dynamic Content

In This Article

Mandrill supports Handlebars for customized content in your emails. Use Handlebars regardless of whether you're using templates in Mandrill. We'll cover the basics of Handlebars, helpers implemented specifically for Mandrill, and some deviations from and additions to standard Handlebars.

Handlebars Basics

  • A handlebars expression is {{, some contents, followed by }}.

Handlebars templates are made up of data, paths, helpers, partials, and comments:

  • Data: Your content—anything not in a handlebars expression.
  • Paths: How you inject content into templates. For example, {{my.thing}} looks in the merge values provided and gets the thing key in the my hash table.

Escaping: If you have {{thing}} in your template that you want to be viewed as template data instead of a path, use \ to escape it. So \{{thing}} will print "{{thing}}" into the template, and \\{{thing}} will print \ to the template, and then render the path "thing".

  • Helpers: Help you do more complex things rather than printing a value escaped or unescaped. Helpers can be inline, where they operate only on template paths, or block, where they themselves can have template data, nested paths, and else branches. Helpers are generally either one or the other, and all helpers must be registered and defined by Mandrill.

Helpers

Using helpers

Inline helpers are used as:

{{helperName arg1 arg2 arg3}}

Block helpers are used as:

{{#helperName arg 1 arg2}}
other stuff
{{else}}
    else block - helper specific if it's supported and how it works
{{/helperName}}

Inline helpers available in Mandrill

HelperNameFunctionExample
upper uppercase the text provided {{upper "your text"}} results in: YOUR TEXT
lower lowercase the text provided {{lower "your text"}} results in: your text
title title-case the text provided {{title "your text is neat"}} results in: Your Text is Neat
url urlencode the text provided {{url "http://yourawesomeurl.com"}} results in: http%3A%2F%2Fyourawesomeurl.com
date print the current date with a given format, defaults to d/m/Y {{date "Y-m-d"}} results in: 2015-03-10
striptags strip any HTML tags from the given data {{striptags "<p>your text</p>"}} results in: your text

Mandrill also offers another helper, {{unsub}} to add an automatic unsubscribe link to your emails. Generally, you would add the unsub helper in handlebars as {{unsub "http://redirecturl.com"}} where you pass the URL directly in the helper and the URL must be enclosed in double quotes. For example:

<a href='{{unsub "http://redirecturl.com"}}'>Unsubscribe</a>

You can also pass the redirect URL as a merge_var:

<a href='{{unsub redirect_merge_var}}'>Unsubscribe</a>

with the merge var defined as:

   "global_merge_vars": [
        {
            "name": "redirect_merge_var",
            "content": "http://yourdomain.com"
        }
    ]

Note: When using the {{unsub}} helper inside of an anchor tag, be sure to use single quotes around for the href='{{unsub }}'.

Block helpers available in Mandrill

Below are all helpers included with and documented by Handlebars with detailed examples.

The if helper

When using the {{#if}} helper in Handlebars, any expression whose value is not false, undefined, null, "", 0, or [] will evaluate as true.

In your template, you might have something like:

<div class="entry">
  {{#if user_name}}
    <p>Thanks for registering! Your username is {{user_name}}.</p>
  {{/if}}
</div>

And in your API call, you'd provide:

"global_merge_vars": [
  {
    "name": "user_name",
    "content": "Mandrill_User1"
  }
]

For the following result:

<div class="entry">
  <p>Thanks for registering! Your username is Mandrill_User1.</p>
</div>

The unless helper

The {{#unless}} helper was inspired from Ruby's unless conditional operator, and it works in the same way. The content inside the block will be displayed when the expression is evaluated to false, or unless it's true. It's equivalent to if not.

In your template, you might provide:

<div class="entry">
  {{#unless user_name}}
    <p>You haven't chosen a username. Please enter a username to register.</p>
  {{/unless}}
</div>

And in your API request:

"global_merge_vars": [
  {
    "name": "user_name",
    "content": ""
  }
]

For the following result:

<div class="entry">
  <p>You haven't chosen a username. Please enter a username to register.</p>
</div>

The each helper

The {{#each}} helper iterates over each item in an array. The keyword this can be used to reference the current element being iterated.

In your template:

<div class="entry">
<ul>
<li style="list-style: none">{{#each browsers}}</li>
<li>{{this}}</li>
<li style="list-style: none">{{/each}}</li>
</ul>
</div>

In your API request:

"global_merge_vars": [
  {
    "name": "browsers",
    "content": [
      "Chrome",
      "Firefox",
      "Explorer",
      "Safari",
      "Opera"
    ]
  }
]

The final result:

<div class="entry">
<ul>
<li>Chrome</li>
<li>Firefox</li>
<li>Explorer</li>
<li>Safari</li>
<li>Opera</li>
</ul>
</div>

Note: Whenever an expression evaluates to an array, Handlebars will iterate over each item in the array automatically. So the same results that were just displayed could have been achieved with the following template:

<div class="entry">
<ul>
<li style="list-style: none">{{#browsers}}</li>
<li>{{this}}</li>
<li style="list-style: none">{{/browsers}}</li>
</ul>
</div>

The with helper

The {{#with}} helper allows you to shift the context for a section of a template which can be extremely helpful when accessing nested values. It is equivalent to using dot notation.

In your template:

<div class="entry">
<h2>{{incident}}</h2>
<p>Impact: {{impact}}</p>
<p>Created At: {{created_at}}</p>
<p>Updates: {{#with updates}} {{body}} {{/with}}</p>
<p>Updated At: {{updated_at}}</p>
</div>

In your API request:

"global_merge_vars": [
  {
    "name": "incident",
    "content": "Error in connection"
  },
  {
    "name": "impact",
    "content": "none"
  },
  {
    "name": "updates",
    "content": {
      "id": "9e86a19c-9f9b-447d-b4a8-81f9e71efd85",
      "incident_id": "5a99c8c5-e63f-43f0-b375-df0152211bd8",
      "body": "Testing global variables",
      "status": "update",
      "created_at": "2015-02-27T16:01:55+0000",
      "updated_at": "2015-02-27T16:01:55+0000"
    }
  },
  {
    "name": "created_at",
    "content": "2015-02-27T15:27:23+0000"
  },
  {
    "name": "updated_at",
    "content": "2015-02-27T16:02:18+0000"
  }
]

Final result:

<div class="entry">
<h2>Error in connection</h2>
<p>Impact: none</p>
<p>Created At: 2015-02-27T15:27:23+0000</p>
<p>Updates: Testing global variables</p>
<p>Updated At: 2015-02-27T16:02:18+0000</p>
</div>

This could also be accomplished by using dot notation as in this template:

<div class="entry">
<h2>{{incident}}</h2>
<p>Impact: {{impact}}</p>
<p>Created At: {{created_at}}</p>
<p>Updates: {{updates.body}}</p>
<p>Updated At: {{updated_at}}</p>
</div>

Deviations from Standard Handlebars

  • Some helpers aren't currently supported, including lookup, log, helperMissing, or blockHelperMissing helpers. If you see a need for one of these, please let us know the use-case so we can re-evaluate support.
  • Path names are case-insensitive, so {{MYTHING}} and {{mYThing}} and {{mything}} will all print the same thing.
  • Partials are currently unsupported in Mandrill Handlebars.
  • Mandrill Handlebars templates can be rendered in a text context (used for headers and message text parts). In text mode, all values are unescaped and double vs triple-staches don't matter.

Additions to Standard Handlebars

  • Instead of only using {{else}} to mark an else block for a block helper, use an arbitrary number of {{elseif cond}} blocks. These blocks will only run if the {{else}} block would have run, and only if their condition is matched.
  • We've added a very simple "expression" value that can be used as well as numbers, strings, booleans, and paths as argument values, so {{#if i < 5}} will evaluate if the "i" path is less than the number 5.

Additional examples

Comparison expressions

In Mandrill Handlebars, it's possible to compare values using back ticks to surround the comparisons. These can be very helpful when using the if block helper.

In your template:

<div>
  {{#if `purchases > 3`}}
    <ul>
      {{#items}}
        <li>{{this}}</li>
      {{/items}}
    </ul>
  {{/if}}
</div>

In your API request:

"global_merge_vars": [
  {
    "name": "items",
     "content": [
       "Computer",
       "Monitor",
       "Keyboard",
       "1-Year Insurance",
       "Mouse Pad",
       "Mouse"
     ]
  },
  {
    "total_purchases": 6
  }
]

The result:

<div>
<ul>
<li>Computer</li>
<li>Monitor</li>
<li>Keyboard</li>
<li>1-Year Insurance</li>
<li>Mouse Pad</li>
<li>Mouse</li>
</ul>
</div>

Strings can also be used for comparisons, however you'll have make sure to enclose the string in double quotes as single quotes won't work:

In your template:

{{#if `operating_system == "OS X"`}}
  <p>Click here for instructions to install on a Mac</p>
{{elseif `operating_system == "Windows"`}}
  <p>Click here for instructions to install on a PC</p>
{{/if}}

In your API request:

"global_merge_vars": [
  {
    "name": "operating_system",
    "content": "Windows"
  }
]

The result:

<p>Click here for instructions to install on a PC</p>

HTML escaping

Handlebars HTML-escapes values returned by an {{expression}}. If you don't want Handlebars to escape a value, use the "triple-stash", "{{{.

In your template:

<div>
  {{{html_tag_content}}}
</div>

In your API request:

"global_merge_vars": [
  {
    "name": "html_tag_content",
    "content": "This example<br>is all about<br>the magical world of handlebars"
  }
]

The result:

This example
is all about
the magical world of handlebars

Choosing Handlebars as the Merge Language for Your Emails

Mandrill supports Handlebars or merge tags for adding dynamic content to your emails. You can set Handlebars as the default merge language globally for your account, or on a per-message basis via our API or SMTP Integration.

Global account setting

  1. Go to Settings in your Mandrill account.
  2. Click Sending Defaults in the top menu.
  3. From the Merge Language drop-down menu, choose Handlebars.

The Mandrill API

To set the merge language to Handlebars on a per-message basis using the Mandrill API, set the value of merge_language to handlebars in your messages/send or messages/send-template request.

The Mandrill SMTP Integration

If you're using the Mandrill SMTP Integration, add the X-MC-MergeLanguage custom header to your SMTP message with a value Handlebars (case-insensitive).

Once you've included the X-MC-MergeLanguage header, use the X-MC-MergeVars header to define the merge data (regardless of whether you've chosen the Handlebars or MailChimp merge language).

Each header should be a JSON-formatted object, with name/value pairs separated by commas. For example, to assign a global value for "var1" (the merge tag *|VAR1|* or the Handlebars expression {{var1}}), Mandrill expects to receive:

X-MC-MergeVars: {"var1": "global value 1"}

To set a recipient-specific value, use the name _rcpt with the recipient's email address as the value, with the mergevar and value pairs, like this:

X-MC-MergeVars: {"_rcpt": "emailadress@domain.com", "fname": "John", "lname":"Smith"}

 

Note

  • Combining Handlebars with either mc:edit regions or merge tags in a single message isn't supported. You should pick Handlebars or mc:edit regions plus merge tags.

  • If you're exporting templates from your MailChimp account to Mandrill and using Handlebars as your default merge language in Mandrill, we'll convert merge tags to Handlebars for you automatically.

  • If you've set a default merge language for your account on the Sending Defaults page but provide a different option in your API request or custom X-MC-MergeLanguage SMTP header, that option will override your default setting for the account.