Templates
Keep copy out of your application code. Templates are versioned, and every edit bumps the version so a bad change is traceable.
Create
{
"name": "welcome",
"subject": "Welcome to {{ company }}, {{ user.firstName }}",
"html": "<p>Hi {{ user.firstName }} — your plan is {{ plan.tier }}.</p>",
"text": "Hi {{ user.firstName }} — your plan is {{ plan.tier }}."
}The response lists every variable the template references, which is what you want to render a preview form against.
Syntax
{{ path.to.value }} substitutes a value and escapes it for HTML. {{{ path }}} inserts it raw. Dotted paths and array indexes both resolve.
Escaped by default
Template data usually originates with your end users. Escaping by default means a display name containing <script> renders as text rather than executing in your recipient’s webmail. Only use the raw form for markup you generated yourself.
No logic, deliberately
There are no loops, conditionals or expressions. Templates are rendered inside a shared runtime alongside other tenants’ work, and anything Turing-complete there is both a sandbox-escape surface and a denial-of-service vector. When you need logic, render it in your own application and send html directly.
Preview
{ "data": { "user": { "firstName": "Ada" } } }{
"subject": "Welcome to , Ada",
"html": "<p>Hi Ada — your plan is .</p>",
"missing": ["company", "plan.tier"],
"wouldFail": true
}Preview applies exactly the rule the send path applies: a template referencing a variable you did not supply fails the send rather than mailing a half-written message with a blank in it. wouldFail tells you in advance.
Send with a template
{
"from": "hello@yourdomain.com",
"to": "ada@example.com",
"subject": "ignored when templateId is set",
"templateId": "welcome",
"templateData": {
"company": "Acme",
"user": { "firstName": "Ada" },
"plan": { "tier": "Pro" }
}
}templateId accepts either the id or the name, and cannot be combined with html or text.