Guides

Templates

Server-side rendered email templates with immutable versions and {{ variable }} substitution.

Templates are stored, versioned, and rendered server-side: your app sends an alias plus a model, emitd produces the HTML. The active version is immutable — promote a new version when you want to change what's live.

Manage templates in the console or through the API: /v1/templates.

Sending with a template

POST /v1/email
{
  "from": "you@yourdomain.com",
  "to": ["ada@lovelace.io"],
  "template_alias": "receipt",
  "template_model": { "name": "Ada", "total": "$48.00" }
}

When template_alias is set, the template supplies the subject and body before validation runs — you don't need subject/html_body in the request (an unknown alias fails with template_not_found).

Substitution syntax

Templates use {{ variable }} tokens filled from the top-level keys of template_model:

<h1>Hi {{ name }},</h1>
<p>Your total is {{ total }}.</p>
  • Logic-free by design — no conditionals or loops; compose the model in your code.
  • Top-level keys only — {{ name }} reads model.name. Flatten nested data into the model before sending.
  • HTML-escaped in HTML bodies — interpolated values can't inject markup. subject and text_body render raw.
  • Unknown variables render as empty strings, so a missing key silently blanks rather than leaking {{ key }} into the mail.

Versions

EndpointPurpose
POST /v1/templatesCreate the template shell (alias + name)
GET /v1/templatesList all templates, newest first (not paginated)
GET /v1/templates/{alias}Fetch the template with every version
POST /v1/templates/{alias}/versionsPublish a new immutable version (subject + body; activate: true by default)

Rendering always uses the single active version — publishing with activate (default true) deactivates the others first. Conflicting creates return alias_exists (409); a shell without content returns alias_and_name_required (422).

Templates vs. inline bodies

Inline html_body wins for one-off transactional mail. Templates shine when marketing or support edits content without a deploy, or when the same skeleton serves many sends.

On this page