Templates
You write your own HTML. A template holds numbered versions, and a campaign sends one exact version, so what you tested is what goes out. Versions never change once they’re created.
What a template can use
Section titled “What a template can use”Templates use the Liquid template language, with these values:
| Value | What it is |
|---|---|
{{ contact.fields.FNAME }} |
A custom field. Use a default for contacts without it: {{ contact.fields.FNAME | default: "there" }} |
{{ contact.email }} |
The contact’s address |
{{ contact.tags }} |
The contact’s tags, for example {% if contact.tags contains "vip" %} |
{{ unsubscribe_url }} |
The contact’s own unsubscribe link. Required in the HTML. |
{{ footer_address }} |
Your physical mailing address from settings. Required in the HTML. |
Values in the HTML are escaped; the subject isn’t. Templates can’t include files or other templates: include, render, layout and block aren’t allowed. Each version needs a subject, html, fromName and a fromEmail on your sending domain, and can have a preheader, a plain-text text part and a replyTo. Without text, we generate it from the HTML.
Every email also gets List-Unsubscribe and List-Unsubscribe-Post headers for one-click unsubscribe, a Feedback-ID and Precedence: bulk. You don’t add them.
Create a template
Section titled “Create a template”curl -X POST "$BASE/templates" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{ "name": "Monthly update", "version": { "subject": "Your {{ contact.fields.plan | default: \"account\" }} update for October", "preheader": "What changed this month, in two minutes.", "html": "<p>Hi {{ contact.fields.FNAME | default: \"there\" }},</p><p>Here is what is new.</p><p><a href=\"{{ unsubscribe_url }}\">Unsubscribe</a><br>{{ footer_address }}</p>", "fromName": "Example Co", "fromEmail": "news@example.com", "replyTo": "hello@example.com" }}'The response is the template with version 1. Check its warnings: you get one when the HTML is over 102 KB, because Gmail clips larger messages, and one when there’s no preheader.
Check it worked: the template has an id starting tp_ and latestVersion 1.
A template without the unsubscribe link or the footer is refused:
# Expect 422 template_invalidcurl -X POST "$BASE/templates" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \ -d '{"name":"No footer","version":{"subject":"Hi","html":"<p>Hi</p>","fromName":"Example Co","fromEmail":"news@example.com"}}'Preview it
Section titled “Preview it”Render the latest version with sample values:
curl -X POST "$BASE/templates/<tp_...>/render" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \ -d '{"sample":{"fields":{"FNAME":"Ada","plan":"pro"}}}'Or with one of your contacts. Get a contact ID first:
curl "$BASE/contacts?limit=1" -H "Authorization: Bearer $KEY"
curl -X POST "$BASE/templates/<tp_...>/render" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \ -d '{"contactId":"<ct_...>"}'The response has the subject, html, text and headers exactly as the email would be sent. A Liquid error gives 422 render_failed.
Add a version
Section titled “Add a version”curl -X POST "$BASE/templates/<tp_...>/versions" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{ "subject": "Your October update", "preheader": "What changed this month, in two minutes.", "html": "<p>Hi {{ contact.fields.FNAME | default: \"there\" }},</p><p>Here is what is new, now with pictures.</p><p><a href=\"{{ unsubscribe_url }}\">Unsubscribe</a><br>{{ footer_address }}</p>", "fromName": "Example Co", "fromEmail": "news@example.com"}'
curl "$BASE/templates/<tp_...>" -H "Authorization: Bearer $KEY"Check it worked: the template shows latestVersion 2, and versions lists the newest 20, newest first. GET /templates/<tp_...>/versions lists every version, newest first, a page at a time.
Send from your own domain only
Section titled “Send from your own domain only”fromEmail must be on your verified sending domain:
# Expect 422 from_domain_unverifiedcurl -X POST "$BASE/templates" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \ -d '{"name":"Wrong domain","version":{"subject":"Hi","html":"<a href=\"{{ unsubscribe_url }}\">u</a> {{ footer_address }}","fromName":"Example Co","fromEmail":"news@example.org"}}'Send yourself a test with POST /campaigns/{id}/test before you schedule.