Personalize Emails with Handlebars in MSG91
What is Handlebars and How to Use It in MSG91?
Handlebars is a simple, logic-less templating engine that lets you create dynamic email content using expressions inside double curly braces ({{}}
). MSG91 supports Handlebars helpers to help you personalize emails at scale without needing multiple templates.
Supported Conditional Statements in MSG91 Handlebars:
Basic
if
,else
,else if
if
with root contextunless
greaterThan
greaterThan
withelse
lessThan
lessThan
withelse
Equals
Equals with else
notEquals
notEquals with else
And without else
And with else
Basic or
Or with else
Length
Iterations
Examples of Handlebars Helpers with MSG91
Each example includes:
Handlebars Template (logic used)
JSON Sample Data (variables passed)
Resulting HTML Output (what the user sees)
1) Basic If, Else, Else If - (Greet user based on their loyalty tier)
Explain the conditional logic that personalizes the email based on the user’s loyalty tier.
{{#if user.tier.gold}}
<p>Hello Gold Member! Enjoy exclusive offers just for you.</p>
{{else if user.tier.silver}}
<p>Hello Silver Member! Here's something special for your next order.</p>
{{else}}
<p>Hello Shopper! Unlock rewards by joining our loyalty program.</p>
{{/if}}
How it works:
Checks if the user is a Gold member, shows Gold message.
Else if Silver, shows Silver message.
Otherwise, shows a default message for all others.
JSON – Sample Data You’ll Pass
Show example JSON data where variables match what the template expects.
{
"recipients": [
{
"to": [
{ "name": "test", "email": "[email protected]" }
],
"variables": {
"user": {
"tier": {
"gold": true,
"silver": false
}
}
}
},
{
"to": [
{ "name": "test2", "email": "[email protected]" }
],
"variables": {
"user": {
"tier": {
"gold": false,
"silver": true
}
}
}
},
{
"to": [
{ "name": "test3", "email": "[email protected]" }
],
"variables": {
"user": {
"tier": {
"gold": false,
"silver": false
}
}
}
}
],
"from": {
"name": "Test",
"email": "[email protected]"
},
"domain": "testtest.com",
"template_id": "testtemplate"
}
Note:
true
means the tier applies to that user.Only one tier should be
true
per user for correct output.
HTML – Final Output Your Users Will See
Show the rendered email content for each test case:
<!-- Test data 1 -->
<p>Hello Gold Member! Enjoy exclusive offers just for you.</p>
<!-- Test data 2 -->
<p>Hello Silver Member! Here's something special for your next order.</p>
<!-- Test data 3 -->
<p>Hello Shopper! Unlock rewards by joining our loyalty program.</p>
2) If with a root - (Show support contact if user account is suspended)
Handlebars Template (with root and nested variable) handlebars Copy Edit
{{#if user.suspended}}
<p>Warning! Your account is suspended, please call: {{@root.supportPhone}}</p>
{{/if}}
// Test data
{
"user": {
"suspended": true
},
"supportPhone": "1-800-555-5555"
}
<!-- Resulting HTML -->
<p>Warning! Your account is suspended, please call: 1-800-555-5555</p>
3) Unless - (Show reminder message if the user hasn't placed an order)
<!-- Template -->
{{#unless user.hasOrdered}}
<p>You haven't placed an order yet. Use code <strong>WELCOME10</strong> to get 10% off your first purchase!</p>
{{/unless}}
// Test data 1: User has not ordered
{
"user": {
"hasOrdered": false
}
}
// Test data 2: User has ordered
{
"user": {
"hasOrdered": true
}
}
<!-- Resulting HTML -->
<!-- Test data 1 output -->
<p>You haven't placed an order yet. Use code <strong>WELCOME10</strong> to get 10% off your first purchase!</p>
<!-- Test data 2 output -->
<!-- No output shown, since the user has already placed an order -->
4) greaterThan
Basic greaterThan - (Show high-value alert if the user’s balance exceeds a certain amount)
<!-- Template -->
{{#if (greaterThan user.balance 100000)}}
<p>Alert: Your account balance exceeds ₹1,00,000. Consider investing to grow your savings.</p>
{{/if}}
// Test data 1: Balance is more than 100000
{
"user": {
"balance": 125000
}
}
// Test data 2: Balance is less than 100000
{
"user": {
"balance": 45000
}
}
<!-- Resulting HTML from test data one-->
<!-- Test data 1 output -->
<p>Alert: Your account balance exceeds ₹1,00,000. Consider investing to grow your savings.</p>
<!-- Test data 2 output -->
<!-- No output, since balance is below threshold -->
5) greaterThan with else - (Show free shipping if cart value exceeds ₹2000, else suggest how much more to add)
<!-- Template -->
{{#if (greaterThan cart.total 2000)}}
<p>Congrats! You're eligible for <strong>Free Shipping</strong>.</p>
{{else}}
<p>Add items worth ₹{{subtract 2000 cart.total}} more to unlock <strong>Free Shipping</strong>.</p>
{{/if}}
// Test data 1: Cart total > 2000
{
"cart": {
"total": 2300
}
}
// Test data 2: Cart total < 2000
{
"cart": {
"total": 1450
}
}
<!-- Resulting HTML from test data one-->
<!-- Test data 1 output -->
<p>Congrats! You're eligible for <strong>Free Shipping</strong>.</p>
<!-- Test data 2 output -->
<p>Add items worth ₹550 more to unlock <strong>Free Shipping</strong>.</p>
6) lessThan
Basic lessThan - (Show encouragement if the student scored below 50%)
{{#if (lessThan user.score 50)}}
<p>Don't give up! You scored below 50%. Here's a free revision module to help you improve.</p>
{{/if}}
// Test data 1: Score less than 50
{
"user": {
"score": 42
}
}
// Test data 2: Score 50 or above
{
"user": {
"score": 78
}
}
<!-- Resulting HTML from test data one-->
<!-- Test data 1 output -->
<p>Don't give up! You scored below 50%. Here's a free revision module to help you improve.</p>
<!-- Test data 2 output -->
<!-- No output, since the score is not less than 50% -->
7) lessThan with else - (Encourage user if steps are low, celebrate if steps are good)
<!-- Template -->
{{#if (lessThan user.dailySteps 5000)}}
<p>You’ve taken {{user.dailySteps}} steps today. Let’s aim for 5,000! A short walk can make a big difference.</p>
{{else}}
<p>Great job! You've completed {{user.dailySteps}} steps today. Keep up the healthy habit!</p>
{{/if}}
// Test data 1: Less than 5000 steps
{
"user": {
"dailySteps": 3200
}
}
// Test data 2: 5000 steps or more
{
"user": {
"dailySteps": 7200
}
}
<!-- Resulting HTML from test data one-->
<!-- Test data 1 output -->
<p>You’ve taken 3200 steps today. Let’s aim for 5,000! A short walk can make a big difference.</p>
<!-- Test data 2 output -->
<p>Great job! You've completed 7200 steps today. Keep up the healthy habit!</p>
8) Equals -
Basic equals - (Checking if the user has a winning code)
<!-- Template -->
<p>
Hello Ben!
{{#equals customerCode winningCode}}
You have a winning code.
{{/equals}}
Thanks for playing.
</p>
// Test data one
{
"customerCode": 289199,
"winningCode": 289199
}
// Test data two
{
"customerCode": 167320,
"winningCode": 289199
}
<!-- Resulting HTML from test data one-->
<p>Hello Ben! You have a winning code. Thanks for playing.</p>
<!-- Resulting HTML from test data two-->
<p>Hello Ben! Thanks for playing.</p>
9) Equals with else - (Show a winning or non-winning message based on code match)
<!-- Template -->
<p>
Hello Ben!
{{#equals customerCode winningCode}}
You have a winning code.
{{else}}
You do not have a winning code.
{{/equals}}
Thanks for playing.
</p>
// Test data one
{
"customerCode": 289199,
"winningCode": 289199
}
// Test data two
{
"customerCode": 167320,
"winningCode": 289199
}
<!-- Resulting HTML from test data one-->
<p>Hello Ben! You have a winning code. Thanks for playing.</p>
<!-- Resulting HTML from test data two-->
<p>Hello Ben! You do not have a winning code. Thanks for playing.</p>
10) notEquals - (Show a message if the user’s appointment is not today)
<!-- Template -->
<p>
Hello Ben!
{{#notEquals currentDate appointmentDate}}
Your appointment is not today.
{{/notEquals}}
We look forward to your visit.
</p>
// Test data one
{
"currentDate": 20230715,
"appointmentDate": 20230715
}
// Test data two
{
"currentDate": 20230710,
"appointmentDate": 20230715
}
<!-- Resulting HTML from test data one-->
<p>Hello Ben! We look forward to your visit.</p>
<!-- Resulting HTML from test data two-->
<p>Hello Ben! Your appointment is not today. We look forward to your visit.</p>
11) notEquals with else - (Show different messages depending on whether today is the appointment date)
<!-- Template -->
<p>
Hello Ben!
{{#notEquals currentDate appointmentDate}}
Your appointment is not today.
{{else}}
Your appointment is today.
{{/notEquals}}
We look forward to your visit.
</p>
// Test data one
{
"currentDate": 20230715,
"appointmentDate": 20230715
}
// Test data two
{
"currentDate": 20230710,
"appointmentDate": 20230715
}
<!-- Resulting HTML from test data one-->
<p>Hello Ben! Your appointment is today. We look forward to your visit.</p>
<!-- Resulting HTML from test data two-->
<p>Hello Ben! Your appointment is not today. We look forward to your visit.</p>
12) And
And without else - (Show a message only if both favorite food and drink are provided)
<!-- Template -->
<p>
Hello Ben!
{{#and favoriteFood favoriteDrink}}
Thank you for letting us know your dining preferences.
{{/and}}.
We look forward to sending you more delicious recipes.</p>
// Test data one
{
"favoriteFood": "Pasta",
"favoriteDrink": ""
}
// Test data two
{
"favoriteFood": "Pasta",
"favoriteDrink": "Coffee"
}
<!-- Resulting HTML from test data one -->
<p>Hello Ben! We look forward to sending you more delicious recipes.</p>
<!-- Resulting HTML from test data two -->
<p>
Hello Ben! Thank you for letting us know your dining preferences. We look forward
to sending you more delicious recipes.
</p>
13) And with else - Personalizing Follow-Up Based on Input Completion
<!-- Template -->
<p>
Hello Ben!
{{#and favoriteFood favoriteDrink}}
Thank you for letting us know your dining preferences.
{{else}}
If you finish filling out your dining preferences survey, we can deliver you recipes we think you'll be most interested in.
{{/and}}.
We look forward to sending you more delicious recipes.</p>
// Test data one
{
"favoriteFood": "Pasta",
"favoriteDrink": ""
}
// Test data two
{
"favoriteFood": "Pasta",
"favoriteDrink": "Coffee"
}
<!-- Resulting HTML from test data one -->
<p>
Hi Ben! If you finish filling out your dining preferences survey, we can
deliver you recipes we think you'll be most interested in. We look forward to
sending you more delicious recipes.
</p>
<!-- Resulting HTML from test data two -->
<p>
Hi Ben! Thank you for letting us know your dining preferences. We look forward
to sending you more delicious recipes.
</p>
14) Basic or - Suggesting Content Based on Interests
<!-- Template -->
<p>
Hello Ben!
{{#or isRunner isCyclist}}
We think you might enjoy a map of trails in your area.
{{/or}}.
Have a great day.
</p>
// Test data one
{
"isRunner": true,
"isCyclist": false
}
// Test data two
{
"isRunner": false,
"isCyclist": false
}
// Test data three
{
"isRunner": false,
"isCyclist": true
}
<!-- Resulting HTML from test data one -->
<p>
Hi Ben! We think you might enjoy a map of trails in your area. You can find
the map attached to this email. Have a great day.
</p>
<!-- Resulting HTML from test data two -->
<p>Hi Ben! Have a great day.</p>
<!-- Resulting HTML from test data three -->
<p>
Hi Ben! We think you might enjoy a map of trails in your area. You can find
the map attached to this email. Have a great day.
</p>
15) Or with else - Personalizing Based on Known or Unknown Interests
<!-- Template -->
<p>
Hello Ben!
{{#or isRunner isCyclist}}
We think you might enjoy a map of trails in your area. You can find the map attached to this email.
{{else}}
We'd love to know more about the outdoor activities you enjoy. The survey linked below will take only a minute to fill out.
{{/or}}.
Have a great day.
</p>
// Test data one
{
"isRunner": true,
"isCyclist": false
}
// Test data two
{
"isRunner": false,
"isCyclist": false
}
// Test data three
{
"isRunner": false,
"isCyclist": true
}
<!-- Resulting HTML from test data one -->
<p>
Hi Ben! We think you might enjoy a map of trails in your area. You can find
the map attached to this email. Have a great day.
</p>
<!-- Resulting HTML from test data two -->
<p>
Hi Ben! We'd love to know more about the outdoor activities you enjoy. The
survey linked below will take only a minute to fill out. Have a great day.
</p>
<!-- Resulting HTML from test data three -->
<p>
Hi Ben! We think you might enjoy a map of trails in your area. You can find
the map attached to this email. Have a great day.
</p>
16) Length - You want to remind users if they have items left in their cart.
<!-- Templates -->
<p>
Hello Ben!
{{#greaterThan (length cartItems) 0}}
It looks like you still have some items in your shopping cart. Sign back in to continue checking out at any time.
{{else}}
Thanks for browsing our site. We hope you'll come back soon.
{{/greaterThan}}
</p>
Copy code block
// Test data one
{
"cartItems": ["raft", "water bottle", "sleeping bag"]
}
// Test data two
{
"cartItems": []
}
<!-- Resulting HTML with test data one-->
<p>
Hello Ben! It looks like you still have some items in your shopping cart. Sign
back in to continue checking out at any time.
</p>
<!-- Resulting HTML with test data two-->
<p>Hello Ben! Thanks for browsing our site. We hope you'll come back soon.</p>
17) Iterations
You can use the {{#each}}
helper to loop through data, such as lists or arrays, and display each item in your email template.
Basic Iterator with each - You want to show customers a list of their recent orders to remind them of their purchase history.
<!-- Template -->
<ol>
{{#each user.orderHistory}}
<li>You ordered: {{this.item}} on: {{this.date}}</li>
{{/each}}
</ol>
// Test data
{
"user": {
"orderHistory": [
{
"date": "2/1/2025",
"item": "shoes"
},
{
"date": "1/4/2025",
"item": "hat"
}
]
}
}
<!-- Resulting HTML -->
<ol>
<li>You ordered: shoes on: 2/1/2018</li>
<li>You ordered: hat on: 1/42017</li>
</ol>
Combined examples -
The following examples demonstrate how to combine multiple Handlebars helpers to create dynamic, personalized email templates.
1) Dynamic content creation
<!-- Template -->
{{#each user.story}}
{{#if this.male}}
<p>{{this.date}}</p>
{{else if this.female}}
<p>{{this.item}}</p>
{{/if}}
{{/each}}
// Test data
{
"user": {
"story": [
{
"male": true,
"date": "2/1/2018",
"item": "shoes"
},
{
"male": true,
"date": "1/4/2017",
"item": "hat"
},
{
"female": true,
"date": "1/1/2016",
"item": "shirt"
}
]
}
}
<!-- Resulting HTML -->
<p>2/1/2018</p>
<p>1/4/2017</p>
<p>shirt</p>
2) Dynamic content creation with dynamic parts 1
<!-- Template -->
{{#each user.story}}
{{#if this.male}}
{{#if this.date}}
<p>{{this.date}}</p>
{{/if}}
{{#if this.item}}
<p>{{this.item}}</p>
{{/if}}
{{else if this.female}}
{{#if this.date}}
<p>{{this.date}}</p>
{{/if}}
{{#if this.item}}
<p>{{this.item}}</p>
{{/if}}
{{/if}}
{{/each}}
// Test data
{
"user": {
"story": [
{
"male": true,
"date": "2/1/2018",
"item": "shoes"
},
{
"male": true,
"date": "1/4/2017"
},
{
"female": true,
"item": "shirt"
}
]
}
}
<!-- Resulting HTML -->
<p>2/1/2018</p>
<p>shoes</p>
<p>1/4/2017</p>
<p>shirt</p>
3) Dynamic content creation with dynamic parts 2
<!-- Template -->
{{#if people}}
<p>People:</p>
{{#each people}}
<p>{{this.name}}</p>
{{/each}}
{{/if}}
// Test data
{
"people": [{ "name": "Bob" }, { "name": "Sally" }]
}
<!-- Resulting HTML -->
<p>People:</p>
<p>Bob</p>
<p>Sally</p>
Example Use Case: Order Confirmation Email Using Handlebars
Objective:
Send a personalized order confirmation email that dynamically includes the customer’s name and lists all the items they purchased, with quantity and pricing.
User Scenario:
Riya places an order on your eCommerce website. She buys:
1 Black Dress – ₹1,499
2 Lipsticks – ₹299 each
Instead of hardcoding product details or creating different templates for every order, you use Handlebars to dynamically populate the data.
Data Sent to MSG91 (via API or platform)
"first_name": "Riya",
"order_id": "ORD10293",
"order": {
"items": [
{ "name": "Black Dress", "quantity": 1, "price": 1499 },
{ "name": "Lipstick", "quantity": 2, "price": 299 }
]
}
}
Handlebars-Based Email Template
<h2>Hello {{first_name}},</h2>
<p>Thanks for your purchase! Here are your order details:</p>
<h3>Order ID: {{order_id}}</h3>
<table width="100%" cellpadding="10" cellspacing="0" border="1">
<thead>
<tr>
<th>Product</th>
<th>Qty</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{{#each order.items}}
<tr>
<td>{{name}}</td>
<td>{{quantity}}</td>
<td>₹{{price}}</td>
</tr>
{{/each}}
</tbody>
</table>
<p>We hope you enjoy your purchase. </p>
Output Received by Riya
Hello Riya,
Thanks for your purchase! Here are your order details:
Order ID: ORD10293
Product | Qty | Price
-------------------------------
Black Dress | 1 | ₹1499
Lipstick | 2 | ₹299
We hope you enjoy your purchase. Hello Riya,
Benefits of Using Handlebars
Without Handlebars | With Handlebars in MSG91 |
---|---|
You send each order email individually | Use one dynamic template for every order. |
Multiple emails flying everywhere - hard to track issues | Always accurate and personalized using live data. |
Credits wasted sending separate emails for each order | Save credits — one smart email covers everything. |
1. Log in to Your MSG91 Email Account
Open your MSG91 Dashboard.
2. Go to Templates and Click “Create Template”
Navigate to the Email section → Templates → Click Create Template.
3. Choose “Start from Scratch” or Use AI
You can either:
Build a new template from scratch, or
Use “Generate via AI” and then enhance it with Handlebars
4. Insert Handlebars in the Email Body
Use Handlebars directly in your HTML editor to dynamically display personalized content based on the order data.
5. Test Your Template
Click Preview or use sample JSON data to see your template in action. MSG91 will render real-time results based on your test data.
6. Submit for Approval and Launch
Once your template is ready:
Submit for approval.
After approval, use it in your transactional flows or campaigns.
Done! Your personalized template is live.
Why Use It?
Dynamic, personalized emails at scale
Great for order updates, cart recovery, offers, and more
Compatible with automation and transactional flows
Need Help?
If you’re unsure about your data format or template logic, our team is here to assist.
Email: [email protected]
Live Chat: Available on MSG91 Dashboard