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.
info |
Note MoEngage currently supports Jinja version 2.8. |
Variables
Variables can also be expressions, which evaluate a new variable. Anything inside double brackets is evaluated and inserted into the final content.
Often a variable is a collection of attributes. In the MoEngage email template, these attributes can be accessed using a dot operator:
.
Or with a subscript notation:
[]
To insert variables, enclose them in double braces. For example, to insert the user attribute labeled FirstName:
{{UserAttribute['First Name']}}
For example, UserAttributes is a collection of all attributes belonging to the current user. If you want to insert the value of the attribute FirstName, use the following code:
Welcome, {{UserAttribute['First Name']}}
info |
Note
|
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.
To use Expressions or Statements, enclose them as follows:
{% %}
Literals
Literals are the simplest form of expression. Literals represent variables such as 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. |
Expression Tests
Tests can be used to test a variable against a common expression. To test a variable or expression, add is and 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 the name is defined in the current context of the template.
Tests can accept arguments also. If the test only takes one argument, you can leave out the parentheses. For example, the following two expressions do the same thing:
{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}
For more information, refer to Jinja Pallets.
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:
{% # note: commented-out template because we no longer use this
{% for user in users %}
...
{% endfor %}
# %}
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:
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
Conditional statements, loops
- Now client can use the custom variable with loop:
Tags control the logic of the template and can perform conditional statements, loops, macros, and so on.
{% set products = [{‘name’: ‘Nike’, ‘href’: 'https://www.example.com/nike'}, {‘name’: ‘Adidas’, ‘href’: 'https://www.example.com/adidas'}] %}
{% for product in products %} <li><a href="{{ product.href }}">{{ product.name }}</a></li> {% endfor %}
Sample condition
{% if products
%}
<p>The products is not empty.</p>
{% else %}
<p>The products is empty.</p>
{% endif %}
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 must 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 is 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:
{{UserAttribute['First Name']|e}}
Control Structures
A control structure refers to all those things that control the flow of a program:
- conditionals (that is, if/elif/else)
- for-loops
- 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:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
Within a for-loop, it’s possible to cycle among a list of strings or variables each time through the loop by using the special cycle helper:
{% 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:
{% 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:
{% 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 %}
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 window that provides options to handle the situation where an attribute returns a null.
To ensure the message isn’t sent when an attribute value is missing, set the fallback value to Do not send if the variable is null. The MoEngage email template displays an overlay pop-up window with options for handling unsent messages.
The option selected by you will be automatically used while sending messages based on 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
{% set firstName = UserAttribute['First name'] %}
{% if firstName %}
Welcome, {{ firstName }}
{% else %}
Welcome!
{% endif %}
If you don't want to send the message and if the value of the attribute is not found, you can use
Welcome, {{UserAttribute['First name']|default('MOE_NOT_SEND')}}
Jinja Filters (Functions)
The following are a few of the global functions supported by Jinja:
String Filters
Convert to Proper Case/ Title Case
This will allow you to convert a string to Title case. For example:
Input: joHn doE
Output: John Doe
{{UserAttribute['FirstName']|title}}
Capitalize First Letter
This will allow you to capitalize the first letter of each sentence in a string. For example:
Input: joHn doE. his age is 20.
Output: John doe. His age is 20.
{{UserAttribute['FirstName']|capitalize}}
Upper Case
This will allow you to convert a string to uppercase. For example:
Input: joHn doE
Output: JOHN DOE
{{UserAttribute['FirstName']|upper}}
Lower Case
This will allow you to convert a string to lowercase. For example:
Input: JoHn doE
Output: john doe
{{UserAttribute['FirstName']|lower}}
Replace a String
This will allow you to replace a part of a string with another string. For example, let's replace "jo" in joHn with "ma":
Input: joHn doE
Output: mahn doe
{{UserAttribute['Mobile Number']|replace(“jo”,”ma”)}}
Check if a String Contains a Substring
This will allow you to check if a string contains a substring. For example:
Input String: Click on me now!
Input Substring: now
Output: true block
{% if "true" in UserAttribute['eligible'] %} true block {% elif "false" in UserAttribute['eligible'] %} false block {% endif %}
Number Filters
Add +91
This will allow you to replace a part of add "+91" to a mobile number. For example:
Input: 9991119991
Output: +919991119991
{{“+91” + UserAttribute['Mobile Number']|default('NA')}}
Consider 10 digits
This will allow you to consider only 10 digits of a mobile number. For example:
Input: +919991119991
Output: 9991119991
{{UserAttribute['Mobile Number'][-10:]|default('NA')}}
Integer Filters
Bit Length of Data
Returns the number of bits necessary to represent an integer in binary, excluding the sign and leading zeros.
int.bit_length()
Conjugate of the Complex Number
Returns the conjugate of the complex number. Complex numbers are not supported, so int.conjugate() returns the number itself.
int.conjugate()
Float Filters
Identify whether the Float is a Finite Integer
Returns True if the float instance is finite with integral value, and False otherwise.
<span">float.is_integer()</span">
Hexadecimal String
Returns float represented by a hexadecimal string. The string may have leading and trailing whitespace.
float.fromhex(string)
Conjugate of the Complex Number
Returns the conjugate of the complex number. Complex numbers are not supported, so float.conjugate() returns the number itself.
float.conjugate()
List Filters
Occurrences of an Item
Returns the number of occurrences of the given item in the List.
list.count(item)
Lowest Index in the List
Returns the lowest index in the List where the given item is found within the slice s[start:end]. Optional arguments start and end are interpreted as in slice notation. Similar to str.index().
list.index() throws an error if index not within the List.
list.index(item[, start[, end]])
Remove Item at Index Position in the List
Returns the item at index position in List and also removes it from the List. If no index provided, returns and removes the last item in the list. list.pop() throws an error if index not within the List.
list.pop([index])
info |
Information MoEngage currently supports all other standard functions of Jinja. If you want to learn more about standard functions in Jinja, refer to List of Global Functions. |
Custom Functions
Date Time Functions and Formatters
Date Formatter - Converts any given date to the format mentioned in toFormat.
Usage
{{'14/10/2020'|dateFormatter('%m/%d/%Y')}}
Output: 10/14/2020
Date Difference - Returns the difference between 2 dates. Return values can be positive, zero, or negative.
Usage
{{'12/10/2020'|days('14/10/2020')}}
Output: 2
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')}}
Output: 05/23/2024
Date and Time Formatter Function -
- 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')}}
Output: 2012-01-19 05:21:00 PM
- 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')}}
Output:
2012-01-19 11:51:00 AM
2012-01-19 22:51:00 PM
info |
Note
|
For more formats, refer to: https://strftime.org/
Strikethrough Text
This will allow you to strikethrough the text. For example, you want to show the old price of a product in strikethrough.
Input: Price USD 100
Output: Price USD 100
Price USD <s>{{100}}</s>
Encryption and Decryption
SHA 256 Encryption
Jinja now supports SHA 256 encryption in two ways:
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')}}
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()}}
Base64 Encoding
Encrypts the string using Base64 encoding.
Usage
{{UserEmail|base64encode()}}
URL Encoding
Encrypts the string using URL encoding.
Usage
{{UserEmail|uerlencode()}}
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. |