Templates
A template is a reusable subject and body with variables in it. Every new account starts with five: welcome, verify email, password reset, payment receipt, and a product update.
Sending one
curl -X POST https://app.mailstein.com/api/v1/emails \
-H "Authorization: Bearer $MAILSTEIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"to": "someone@example.com",
"templateId": "cmsm9pt1b0017vseua7veqnqi",
"variables": { "firstName": "Sam", "companyName": "Acme" }
}'
subject and html are not needed when you pass a templateId — they come
from the template. Pass a subject anyway and it overrides the template's.
Drafts and publishing
What you edit is a draft. What sends is the published version, and the two are separate on purpose: before that separation existed, opening a template and half-finishing an edit changed the mail going out that second, and there was no way afterwards to know what had actually been sent.
curl -X POST https://app.mailstein.com/api/v1/templates/$ID/publish \
-H "Authorization: Bearer $MAILSTEIN_API_KEY"
Publishing freezes the current draft as a numbered, immutable version and makes it the one that sends. Edit freely afterwards — nothing reaches a recipient until you publish again.
A template that has never been published cannot be sent with. The API refuses it rather than sending an empty message.
Every version is kept:
curl https://app.mailstein.com/api/v1/templates/$ID/versions \
-H "Authorization: Bearer $MAILSTEIN_API_KEY"
And an earlier one can be put back:
curl -X POST https://app.mailstein.com/api/v1/templates/$ID/rollback \
-H "Authorization: Bearer $MAILSTEIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"versionNumber": 1}'
Rollback points at the existing version rather than copying it forward, so the history stays a record of what was published and when.
Variables
Written {{firstName}} in the subject or the body, and substituted from
variables at send time.
A variable with no value substitutes to an empty string, which is how an email ends up reading "Hi ," in someone's inbox. Give every variable a fallback in the editor, and prefer "Hi there" over a name you might not have.
Creating one over the API
curl -X POST https://app.mailstein.com/api/v1/templates \
-H "Authorization: Bearer $MAILSTEIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Welcome","subject":"Welcome to {{companyName}}","content":"{\"type\":\"doc\",\"content\":[...]}"}'
content is the editor's document format. The HTML is rendered from it and
returned on the response — you cannot set the HTML directly, on purpose: a
template whose stored HTML disagrees with its stored content previews as one
thing and arrives as another, and there is no way to tell afterwards which one
was right.
If you want to send arbitrary HTML, do not use a template. Pass html to
POST /v1/emails instead.
From the CLI
npx -y mailstein-cli emails send \
--from hello@yourdomain.com \
--to someone@example.com \
--template cmsm9pt1b0017vseua7veqnqi \
--var firstName=Sam --var companyName=Acme
--var is repeatable, and --to is too.
Templates and broadcasts
A broadcast carries its own body rather than referencing a template. Reusing a template across many broadcasts is not currently possible; duplicate the template and edit the copy.