Skip to main content
1

A template is a draft until you publish it

email.template.set saves a draft — a subject, HTML, and optionally a plain-text part. Nothing sends from a draft. email.template.publish makes that draft the version email.send uses from then on, and the version it replaces is kept as history.That separation is the whole point of templates existing rather than passing HTML to every send: the copy can be edited, reviewed and previewed without any risk that a half-finished sentence reaches somebody.The plain-text part is derived from the HTML when you omit it, so a text alternative always goes out. HTML is capped at 200,000 characters and text at 100,000.layout decides the frame. brand, the default, wraps your HTML in the project’s themed frame — the same theme the hosted sign-in pages wear. none sends the HTML exactly as written, for when you have designed the whole email yourself.
2

Variables, conditions and loops

{{variable}} interpolates. {{#if}} includes a block when a value is present, and {{#each}} repeats one — enough to render an order’s lines or greet somebody by name without a second template.A syntax error is refused at email.template.set with the line number, rather than being discovered when a send renders to something strange. The draft is not saved.A broadcast supplies each contact’s own properties as variables, so the same template personalises itself per recipient without you assembling anything.
3

Each language is its own variant, versioned on its own

Pass locale to write a variant — fr, pt-BR. Each language has its own draft, its own published version and its own history, so translating one does not disturb another and publishing French does not publish a half-finished German.Omitting locale writes the default variant, which is what a recipient gets when nothing more specific fits them.
4

Start from one of ours, or from nothing

email.template.starter.list returns four emails worth starting from — a welcome, an announcement, a receipt and a plain notice. Each comes back with a subject, the blocks it is built from, the variables it asks for, and html rendered with this project’s theme.Pass that html straight to email.template.set and the template exists. It opens in the dashboard’s block editor, because the bytes are the ones that editor writes — so you can start it from an agent and finish it by hand, or the other way round.They are starting points with placeholder wording, not messages Lath sends. Every {{variable}} in one has to be supplied at send: an unfilled variable is refused, never mailed as {{name}}. The frame already carries your project’s name, footer, postal address and unsubscribe link, so no starter repeats them.
5

Preview before anybody receives it

email.template.preview renders a template with the variables you give it exactly as email.send would, brand frame included, and sends nothing.It reports any variable the template needs that you did not supply — which is how you find the {{firstName}} that renders blank for half your audience, before it does.The default previews what actually sends today. version: "draft" previews unpublished changes instead, and is refused with no_draft when there are none — right after a publish, for example, because publishing is what turns the draft into the sending version. Pass a locale to see what a recipient in that language gets, including which variant the fallback chose for them.email.template.list shows what exists and email.template.get returns one. Some templates are reserved — the sign-in and verification messages Lath sends on your behalf. You can rewrite those too, and the same draft-then-publish rule protects them.
Last modified on September 23, 2026