Smart transactional email and the Liquid template language

Liquid is an open-source language created by Shopify to enable dynamic content. It is supported in our smart transactional email when you import your own email design, allowing you to create invoice item lists, reformat text, show content based on certain conditions and more.

Below are some examples of how Liquid can be used with smart transactional emails. For a quick-start guide on Liquid's syntax and capabilities, we recommend Liquid for designers.

Text formatting

Liquid can manipulate strings in various ways using filters. For example, if you want to say “hi” to your recipient, but would like their name displayed in uppercase in your email regardless of how it is entered in your system, you could use the following:

HI {{ customer_name | upcase }}!

The filter is indicated by the pipe ( | ) symbol, and is followed by the appropriate filter name and parameters, in this case "upcase." Here the Liquid variable "customer_name" is being passed through "upcase," so when we pass the following JSON content containing customer data during a test or API call:

{
  "customer_name": "Sally Sparrow"
}

Sally Sparrow's name is converted to uppercase before send, like so:

HI SALLY SPARROW!

You can just as easily make text lowercase by using "downcase" instead, and perform other string manipulation tasks like slicing, splitting, replacement, reformatting a date and more. Read more about filters.

Conditionals

Liquid supports IF statements, using the syntax:

{% if variable == 'value' %}
  code if true
{% else %}
  code if false
{% endif %}

You can also specify extra conditions using the "elsif" tag.

{% if variable1 == 'value1' %}
  code if variable1 equals value1
{% elsif variable2 == 'value2' %}
  code if variable2 equals value2, but variable1 does not equal value1
{% else %}
  code if no conditions are true
{% endif %}

Like dynamic content in email campaigns, this can be used to show or hide content based on certain conditions.

For example, if you had recipients' countries recorded in your application, you could customize a greeting:

{% if customer.country == 'AU' %}
  G'day {{ customer.name }}!
{% elsif customer.country == 'USA' %}
  Yo {{ customer.name }}!
{% elsif customer.country == 'UK' %}
  Hello there, {{ customer.name }}!
{% else %}
  Greetings, {{ customer.name }}!
{% endif %}

If we then passed in customer data using the following JSON during a test send or API call:

{
  "customer": 
  {
    "name": "Sally Sparrow",
    "country": "AU"
  }
}

The final recipient would see:

G'day Sally Sparrow!

Read more about conditionals.

Constructing an invoice with loops

To create an item list for an invoice, a FOR loop is used. For example, a simple FOR loop that reads from an array called "invoice_list" might look like this:

{% for item in invoice_list %}
  {{ item.description }} | QTY: {{ item.qty }} | COST: ${{ item.cost }} | SUBTOTAL: ${{ item.subtotal }}

{% endfor %}

This block of code will repeat for every item that is passed in, building a list line-by-line, including each item's description, the order quantity, the cost, and the subtotal.

The JSON we'd pass in for a test email or API call, containing the items in said item list, would look something like this:

 {
  "invoice_list": [
    {
      "description": "Brand A Coffee (500g)",
      "qty": 1,
      "cost": 15.95,
      "subtotal": 15.95
    },
    {
      "description": "Brand B Tea (20 bags)",
      "qty": 3,
      "cost": 1.99,
      "subtotal": 5.97
    },
    {
      "description": "Brand C Coffee Mug (Large)",
      "qty": 1,
      "cost": 14.99,
      "subtotal": 14.99
    }
  ]
}

In the example above, there are three items within the "invoice_list" array: Brand A Coffee (500g), Brand B Tea (20 bags) and Brand C Coffee Mug (Large), each with its individual attributes. If this data was passed in, the final email would look like this:

To make things more readable, Liquid can be used inline with HTML and CSS. For example:

<table>
  <tr>
    <td class="description header bold">Item</td>
    <td class="cost header bold">Cost</td>
    <td class="qty header bold">Quantity</td>
    <td class="subtotal header bold">Subtotal</td>
  </tr>
  {% assign invoice_total = 0.00 %}
  {% for item in invoice_list %}
  <tr>
    <td class="description bold">{{ item.description }}</td>
    <td class="cost">${{ item.cost }}</td>
    <td class="qty">x{{ item.qty }}</td>
    <td class="subtotal bold">${{ item.subtotal }}</td>
  </tr>
  {% assign invoice_total = invoice_total | plus: item.subtotal %}
  {% endfor %}
  <tr>
    <td colspan="4"> </td>
  </tr>
  <tr>
    <td colspan="4" class="total bold">TOTAL: ${{ invoice_total }}</td>
  </tr>
</table>

Above is a basic HTML table, with predefined CSS (not shown—download the HTML file for the full example). The Liquid code has has been highlighted so it's easier to see.

We've added more Liquid in this example: an additional variable called "invoice_total" has been initialized outside the loop by assigning it a value of zero, then as each loop finishes for an input item, the item's subtotal is added to the "invoice_total" value using the "plus" filter. This provides a final total when the loop exits.

If you were to preview the example above in a browser, it would look like the image below:

Inputting the exact same JSON above, the email content gets filled out and arrives in the recipient's inbox like the following example:

This is only a basic demonstration of what can be achieved. For more advanced uses, read more about FOR loops.

Handy to know: