MoEngage Templating Language (JINJA)

MoEngage Templating Language is based on Jinja - the popular and simple templating language that enables you to have the highest degree of control over your customization and personalization requirements.

To use it, all you need to do is mark up any variable or message field with syntax as explained in the sections below.

  • To insert Variables, enclose them in double braces  
    {{ }}
    For example, 
    {{UserAttribute.location}}
    inserts the user attribute labeled “location”.
  • To use Tags, they should be enclosed in
    {% %}
    Tags control the logic of the template and can perform conditional statements, loops, macros, etc.
Sample loop:
{% for product in ContentApi.Recommendations().products %}		
    <li><a href="{{ product.href }}">{{ product.name }}</a></li>
{% endfor %}

Variables

Variables can also be expressions, which evaluate a new variable. Anything in a

{{ }}

 gets evaluated and inserted into the final content.

Often a variable is actually a collection of attributes. In the MoEngage email template, these attributes can be accessed using a

.

operator, or with a subscript notation

[]

For example, UserAttributes is a collection of all of the attributes belonging to the current user. If you want to insert the value of the attribute FirstName, either of these will work: 

Welcome, {{ UserAttribute.FirstName }}
Welcome, {{ UserAttribute['FirstName']}}

However, if the defined attribute contains spaces, you need to use the subscript notation: 

Welcome, {{ UserAttribute['First name'] }}

 

Working with Default Values

In the MoEngage email templates, when a message contains a null value, it will not be sent. Hence, we need to assign default fallback values to avoid such situations. In this example, if we don’t have the user’s location, this message would not be sent:   

Welcome to {{ UserAttribute['Location'] }}

To ensure that messages are sent in such a situation, we need to provide a default fallback value that will be returned by the variable in case the value is null. MoEngage email template displays an overlay pop-up where you have different options to handle the situation where an attribute returns a null.

5d92aaf1-31be-4708-ba15-6695728879c7.png

The option selected by you will be automatically used while sending messages as per the value returned. If a default value is provided, then the personalized message looks like this:

Welcome, {{ UserAttribute['First name']|default('Guest') }}

 

Alternatively, we can also use

Jinja
{% set firstName = UserAttribute['First name'] %}
 {% if firstName %}
   Welcome, {{ firstName }}
 {% else %}
   Welcome!
{% endif %}

Contextual Data or Triggered Values

For messages triggered due to some user action or event, we need to provide context-specific details regarding the action or event. If we want to trigger an email to users who have abandoned a shopping cart, we need an “ADDED_TO_CART” event. For example, if we have set the product_name parameter on the ADDED_TO_CART event, and we send the message upon this event being triggered, it can look like

{{ EventAttribute['product_name'] }}

or

{{ EventAttribute.product_name }}
 

Content API

Configure Content API on MoEngage Dashboard. All Content API sources are accessed from the ContentApi variable

Example: You may have a “cart” data source that emits the following JSON:

JSON
{
 "date": "March 10, 2016",
 "items": [
   {
     "name": "belt",
     "image": "http://mydomain.com/images/1001.jpg",
     "price": 11
   }, {
     "name": "shoes",
     "image": "http://mydomain.com/images/1002.jpg",
     "price": 12
   }, {
     "name": "hat",
     "image": "http://mydomain.com/images/1003.jpg",
     "price": 10
   }
 ]
}

To render the cart in a template, you may use the following markup:

Jinja
{% for cart_item in ContentApi.cart().items %}
 <div>
   <h2>{{ cart_item.name }}: ${{ cart_item.price|round(2) }}</h2>
   <img src="{{ cart_item.image }}" />
 </div>
{% endfor %}

 Expression Tests

Tests can be used to test a variable against a common expression. To test a variable or expression, you add is plus the name of the test after the variable. For example, to find out if a variable is defined, you can do name is defined, which will then return true or false depending on whether name is defined in the current template context.

Tests can accept arguments, too. If the test only takes one argument, you can leave out the parentheses. For example, the following two expressions do the same thing:

Jinja
{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}

Comments

To comment out part of a line in a template, use the comment syntax which is by default set to {# ... #}. This is useful to comment out parts of the template for debugging or to add information for other template designers or yourself:

Jinja
{# note: commented-out template because we no longer use this
   {% for user in users %}
       ...
   {% endfor %}
#}

Escaping

It is sometimes desirable – even necessary – to have MoEngage ignore parts it would otherwise handle as variables or blocks. For example, if, with the default syntax, you want to use {{ as a raw string in a template and not to start a variable, you have to use a trick.

The easiest way to output a literal variable delimiter

{{

 is by using a variable expression:

{{ '{{' }}

HTML Escaping

When generating HTML from templates, there’s always a risk that a variable will include characters that affect the resulting HTML.

It’s your responsibility to escape variables if needed. What to escape? If you have a variable that may include any of the following chars

>, <, &, or "

you must escape it unless the variable contains well-formed and trusted HTML. Escaping works by piping the variable through the

|e

filter:

{{ user.Username|e }}

 

List of Control Structures

A control structure refers to all those things that control the flow of a program - conditionals (i.e. if/elif/else), for-loops, as well as things like macros and blocks. With the default syntax, control structures appear inside

{% ... %}

blocks.

For

Loop over each item in a sequence. For example, to display a list of users provided in a variable called users:

HTML
<h1>Members</h1>
<ul>
{% for user in users %}
 <li>{{ user.username|e }}</li>
{% endfor %}
</ul>

Inside of a for-loop block, you can access some special variables:

Variable

Description

loop.index

The current iteration of the loop. (1 indexed)

loop.index0

The current iteration of the loop. (0 indexed)

loop.revindex

The number of iterations from the end of the loop (1 indexed)

loop.revindex0

The number of iterations from the end of the loop (0 indexed)

loop.first

True if first iteration.

loop.last

True if last iteration.

loop.length

The number of items in the sequence.

loop.cycle

A helper function to cycle between a list of sequences. See the explanation below.

loop.depth

Indicates how deep in deep in a recursive loop the rendering currently is. Starts at level 1

loop.depth0

Indicates how deep in deep in a recursive loop the rendering currently is. Starts at level 0

Within a for-loop, it’s possible to cycle among a list of strings/variables each time through the loop by using the special cycle helper:

Jinja
{% for row in rows %}
   <li class="{% cycle('odd', 'even') %}">{{ row }}</li>
{% endfor %}

You can call variables that are defined outside of a loop, from within a loop, but not the other way around.

If

In the simplest form, you can use it to test if a variable is defined, not empty or not false:

Jinja
{% if UserAttribute.interests %}
Your interests:
<ul>
{% for interest in UserAttribute.interests %}
   <li>{{ interest|e }}</li>
{% endfor %}
</ul>
{% endif %}

For multiple branches, elif and else can be used too:

Jinja
{% if UserAttribute.membership == 'Gold' %}
You are a Gold member!
{% elif UserAttribute.membership == 'Silver' %}
You are a Silver member!
{% else %}
Please become a member today!
{% endif %}

Assignments

Inside code blocks, you can also assign values to variables. Assignments at the top level (outside of blocks, macros, or loops) are exported from the template like top-level macros and can be imported by other templates.

Assignments use the set tag and can have multiple targets:

Jinja
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}

 

Expressions

MoEngage supports basic expressions everywhere. Expressions can be used to create variables from other variables or expressions, such as by performing mathematical, logical, or other operations.

Literals

Literals are the simplest form of expressions. Literals represent variables like strings and numbers. The following literals exist:

Literal

Description

“Hello World”

Everything between two double or single quotes is a string. They are useful whenever you need a string in the template (e.g. as arguments to function calls and filters, or just to extend or include a template).

42 / 42.23

Integers and floating point numbers are created by just writing the number down. If a dot is present, the number is a float, otherwise an integer. Keep in mind that 42 and 42.0 are different (int and float, respectively).

['list', 'of', 'objects']

Everything between two brackets is a list. Lists are useful for storing sequential data to be iterated over. For example, you can easily create a list of links using lists and tuples for (and with) a for loop:

<ul> {% for href, caption in [ ('index.html', 'Index'), ('about.html', 'About'), ('downloads.html', 'Downloads') ] %} <li><a href="{{ href }}"> {{ caption }} </a></li> {% endfor %} </ul>
{'dictionary': 'of', 'key':
'and', 'value': 'pairs'}

A dictionary combines keys and values. Keys must be unique and always have exactly one value. Dictionaries are rarely created, but they’re used when reading data from other sources.

true/false

true is always true and false is always false.

 

Math

MoEngage allows you to calculate with values. The following operators are supported:

Operator

Description

+

Adds two objects together. Usually, the objects are numbers, but if both are strings or lists, you can concatenate them this way.

-

Subtract the second number from the first one. {{ 3 - 2 }} is 1.

/

Divide two numbers. The return value will be a floating point number. {{ 1 / 2 }}is {{ 0.5 }}.

%

Calculate the remainder of an integer division. {{ 11 % 7 }} is 4.

*

Multiply the left operand with the right one. {{ 2 * 2 }} would return 4.

 

Comparisons

Operator

Description

==

Compares two objects for equality.

!=

Compares two objects for inequality.

>

True if the left-hand side is greater than the right-hand side.

>=

True if the left-hand side is greater or equal to the right-hand side.

<

True if the left-hand side is lower than the right-hand side.

<=

True if the left-hand side is lower or equal to the right-hand side.

 

Logic

For if statements, filtering, and if expressions, it can be useful to combine multiple expressions:

Operator Description
and Return true if the left and the right operand are true.
or

Return true if the left or the right operand is true. Or can also be used to deal with default values. For example, the following will return the user’s name if it exists; otherwise, it will return the user’s email:

{{ UserAttribute.name or UserAttribute.email }}
not negate a statement
(expr) group an expression. 

 

Other functions

Date Time Functions and formatters

1. Date Formatter - Converts any given date to the format mentioned in toFormat.

Usage
{{'14/10/2020'|dateFormatter('%m/%d/%Y')}}

2. Date Difference - Returns the difference between 2 dates. Return values can be positive, zero, or negative.

Usage
{{'12/10/2020'|days('14/10/2020')}}

3. Today Function - Returns current date in the given format and timezone.

Usage (For a MM/DD/YYYY in EST Timezone)
{{'%m/%d/%Y'|today('EST')}}

4. Date and Time Formatter Function

    a. Format date and time  - Converts any given date to the mentioned format.

Method:
dateTimeFormatter(toFormat='%Y-%m-%d %H:%M:%S %p')

Usage
{{ "2012-01-19 17:21:00 CST" |dateTimeFormatter(toFormat='%Y-%m-%d %H:%M:%S %p')}}

    b. Timezone Conversion - Displays date and time in the respective Timezone, and adds the defined number of minutes to the time.

Method:
dateTimeFormatter(tzOffset=-330)
dateTimeFormatter(timeZone='Asia/Kolkata')

Usage 
{{ "2012-01-19 17:21:00 CST" |dateTimeFormatter(tzOffset=-330)}}
{{ "2012-01-19 17:21:00 CST" |dateTimeFormatter(timeZone='Asia/Kolkata')}}
info

Note

  1. Within dateTimeFormatter filter, multiple methods can be used. For example, to display a user attribute in a particular format and user Timezone, the following code can be used.{{UserAttribute['First Seen']|dateTimeFormatter(toFormat='%Y-%m-%d %H:%M', timeZone='Asia/Kolkata',tzOffset=UserAttribute['User Time Zone Offset (Mins)'])}}
  2. In the case where both the timeZone and tzOffset methods are used, tzOffset is given priority irrespective of the sequence. If the tzOffset value is not available or is -1000, the timeZone method will be used.

For more formats, refer to: https://strftime.org/

SHA 256 Encryption

Jinja now supports SHA 256 encryption in two ways:

1. SHA256 with a Secret Key - Encrypts the string using SHA256 with the secret key

Usage (where 6ABC89W3XY9W is secret key)
{{UserEmail|convertToSHA256('6ABC89P3FXYW')}}

Example
Say you want to encrypt User's Email ID on MoEngage using SHA256
{%set UserEmail=UserAttribute['Email']%}{{UserEmail|convertToSHA256('6ABC89P3FXYW')}}

2. SHA256 without a Secret Key - Encrypts the string using SHA256

Usage
{{UserEmail|convertToSHA256NoSalt()}}

Example
Say you want to encrypt User's Email ID on MoEngage using SHA256
{%set UserEmail=UserAttribute['Email']%}{{UserEmail|convertToSHA256NoSalt()}}

Other Operators

The following operators are very useful but don’t fit into any of the other two categories: 

Operator

Description

in

Perform a sequence/mapping containment test. Returns true if the left operand is contained in the right. {{ 1 in [1, 2, 3] }} would, for example, return true.

is

Performs an expression test.

Was this article helpful?
12 out of 23 found this helpful

How can we improve this article?