SendGrid Dynamic Templates — Reusable Email Designs with Handlebars
In this tutorial, you will learn about SendGrid Dynamic Templates. We cover key concepts, practical examples, and best practices to help you master this topic.
SendGrid dynamic templates use Handlebars syntax to create reusable email designs with dynamic content placeholders, allowing marketing and design teams to update email layouts without developer involvement.
What You'll Learn
- How to create a dynamic template in SendGrid
- How to use Handlebars syntax for personalization
- How to send emails using dynamic templates
Why It Matters
Without dynamic templates, email HTML is embedded in application code. Any design change requires a code deployment. Dynamic templates let designers create and update email designs in the SendGrid UI while developers simply pass data. This decouples email design from application logic.
Real-World Use
DodaTech's marketing team designs all transactional emails (welcome, password reset, invoice) using SendGrid's drag-and-drop editor with Handlebars placeholders. Developers only send the dynamic data. When the marketing team updates the welcome email design, all new users instantly see the new design without any code change.
flowchart LR
A["Marketing Team"] --> B["SendGrid Template\nEditor"]
B --> C["Dynamic Template\nwith {{handlebars}}"]
D["Your App"] -->|"dynamicTemplateData"| E["SendGrid API"]
E --> C
C --> F["Personalized\nEmail"]
style A fill:#fef3c7,stroke:#d97706
style D fill:#dbeafe,stroke:#2563eb
style C fill:#bbf7d0,stroke:#16a34a
Creating a Dynamic Template
Via SendGrid UI or API:
import requests
def create_dynamic_template(name, html_content, subject):
response = requests.post(
"https://api.sendgrid.com/v3/templates",
headers={
"Authorization": f"Bearer {SENDGRID_API_KEY}",
"Content-Type": "application/json"
},
json={
"name": name,
"generation": "dynamic"
}
)
template_id = response.json()["id"]
print(f"Template created: {template_id}")
return template_id
# Add a version to the template
def add_template_version(template_id, subject, html_content):
response = requests.post(
f"https://api.sendgrid.com/v3/templates/{template_id}/versions",
headers={
"Authorization": f"Bearer {SENDGRID_API_KEY}",
"Content-Type": "application/json"
},
json={
"template_id": template_id,
"subject": subject,
"html_content": html_content,
"active": 1
}
)
return response.json()
Handlebars Template Example
<!-- welcome-template.html -->
<!DOCTYPE html>
<html>
<head>
<title>Welcome to {{companyName}}</title>
</head>
<body>
<h1>Welcome, {{userName}}!</h1>
<p>Thank you for creating an account.</p>
<p>Your email: {{userEmail}}</p>
{{#if trialDays}}
<p>You have {{trialDays}} days of free trial remaining.</p>
{{/if}}
<h3>Quick Links</h3>
<ul>
{{#each quickLinks}}
<li><a href="{{url}}">{{label}}</a></li>
{{/each}}
</ul>
<p>Best regards,<br>The {{companyName}} Team</p>
</body>
</html>
Sending with a Dynamic Template
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
def send_template_email(to_email, template_id, template_data):
message = Mail(
from_email='noreply@dodatech.com',
to_emails=to_email
)
# Set the template ID
message.template_id = template_id
# Set dynamic template data
message.dynamic_template_data = template_data
try:
response = sg.send(message)
print(f"Template email sent: {response.status_code}")
return True
except Exception as e:
print(f"Error: {str(e)}")
return False
# Usage
send_template_email(
to_email='user@example.com',
template_id='d-abc123def456',
template_data={
'userName': 'Jane Doe',
'userEmail': 'jane@example.com',
'companyName': 'DodaTech',
'trialDays': 14,
'quickLinks': [
{'label': 'Dashboard', 'url': 'https://dodatech.com/dashboard'},
{'label': 'Profile', 'url': 'https://dodatech.com/profile'},
{'label': 'Help Center', 'url': 'https://help.dodatech.com'}
]
}
)
Common Mistakes
1. Using Legacy Templates Instead of Dynamic
Legacy templates use substitution tags with - delimiters. Dynamic templates use Handlebars {{ }}. Always choose dynamic generation for new templates.
2. Not Escaping Special Characters
Handlebars escapes HTML by default. Use triple braces {{{ }}} for raw HTML, but be careful of XSS risks.
3. Forgetting to Activate a Template Version
Template versions must be activated. An inactive version returns no content. Always set active: 1.
4. Using Handlebars Helpers Incorrectly
Helpers like {{#if}}, {{#each}}, and {{#unless}} must be closed with {{/if}}, {{/each}}. Unclosed helpers break the template.
5. Missing Template Data Fields
If a template references {{userName}} but the data doesn't include it, Handlebars renders an empty string instead of throwing an error. Test with all expected fields.
Practice Questions
- What syntax does SendGrid dynamic templates use?
- How do you specify the template when sending?
- What Handlebars helper iterates over arrays?
- How do you render raw HTML in Handlebars?
- What happens when a template variable is missing?
Answers
- Handlebars
{{ }}syntax. 2. Setmessage.template_idandmessage.dynamic_template_data. 3.{{#each array}}{{/each}}. 4. Use triple braces{{{ }}}. 5. Handlebars renders an empty string.
Challenge
Build a template management system that creates dynamic templates via the SendGrid API, uploads versions with Handlebars content, activates the latest version, and provides a preview endpoint that renders a template with sample data.
FAQ
Mini Project
Build a Python application that manages the full lifecycle of dynamic templates: creates templates and versions via the SendGrid API, uploads Handlebars HTML with conditional blocks and loops, sends test emails with sample data for preview, and promotes versions from draft to active.
What's Next
- Learn about template versioning for managing template changes
- Explore email attachments and inline images
- Continue to categories and unique arguments for email tracking
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro