← Back to blog

Write Emails in Markdown, in the Dashboard or Straight From the API

Tratto templates now take Markdown. Write text, get responsive HTML with a plain-text part. Here's both ways to use it — the editor and the API.

Nobody's favourite part of shipping a product is hand-writing email HTML.

You know the drill: nested tables, inline styles on every element, a <!--[if mso]> block you copied from a Stack Overflow answer in 2019 and have never dared to touch. You test in Gmail, it looks fine. Someone opens it in Outlook and the layout has folded in half.

So Markdown is now a first-class template format in Tratto. Two ways to use it.

In the Dashboard

Go to Templates → New template. The modal asks for a name and a format:

  • HTML — write or paste email HTML directly
  • Markdown — write markdown, responsive HTML is rendered for you

Pick Markdown, and you land in the editor with a starter that doubles as a syntax tour:

# Hello {{firstName}}
 
Write **markdown**, get responsive email HTML — no table soup.
 
::: callout
Use callout blocks for the part people must not miss.
:::
 
[Open your dashboard](https://app.tratto.email)
 
::: footer
Sent with [Tratto](https://tratto.email) · [Unsubscribe]({{unsubscribe_url}})
:::

The preview beside it is rendered on our servers, not drawn by a different engine in your browser — so what you're looking at is the same output that gets sent.

Markdown templates carry an MD badge in the template list, so you can tell the two kinds apart at a glance.

One thing to know before you click create: the format is fixed for the life of the template. A Markdown template derives its HTML from your source, and that's what makes the rest of it safe. If you need to switch, create a new template.

From the API

Same thing, two endpoints.

Save a reusable template:

curl -X POST https://api.tratto.email/v1/templates \
  -H "Authorization: Bearer tratto_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome email",
    "format": "emailmd",
    "markdown": "---\npreheader: Your account is ready\n---\n\n# Welcome aboard, {{name}}\n\nYour workspace is live.\n\n[Open your dashboard](https://app.example.com){button}"
  }'

format: "emailmd" requires markdown and rejects html — the HTML is always derived from your source, never supplied alongside it.

Or skip the template entirely and send Markdown in the message itself:

curl -X POST https://api.tratto.email/v1/emails \
  -H "Authorization: Bearer tratto_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": "[email protected]",
    "to": "[email protected]",
    "subject": "Your report is ready",
    "markdown": "# Your report is ready\n\nWe finished crunching the numbers.\n\n[Download the PDF](https://example.com/report.pdf){button}"
  }'

Useful for the one-off transactional message that doesn't deserve a saved template.

The Syntax You'll Actually Use

Everything standard works — headings, bold, lists, links, images, code. On top of that:

[Confirm](https://…){button}turns a link into a real call-to-action button
::: headera band above the content, usually a logo
::: callouta highlighted card for the part people must not miss
::: footersmaller muted text — legal, unsubscribe
--- frontmatter ---set the preheader — the line inboxes show next to your subject

Note the button is an attribute on a link, not a ::: block. It's the one piece of syntax that doesn't follow the pattern.

Variables Work Exactly As Before

{{firstName}} and friends survive the render untouched, including inside link URLs:

[Confirm your email](https://app.example.com/confirm?token={{token}}){button}

Substitution happens where it always has — at send time, on the final HTML. That ordering isn't incidental: rendering first and substituting second means a contact whose name happens to contain Markdown syntax can't inject formatting into your email.

What You Get Back

Responsive HTML that holds together in Outlook and adapts to dark mode.

A text/plain part, generated from the same source. Almost everyone skips this by hand, and it costs twice: some recipients genuinely read it — screen readers, low-bandwidth clients — and spam filters notice an HTML-only message.

Stability. Your Markdown is rendered once, when you save, and the resulting HTML is stored with the template. We don't re-render at delivery. So an improvement to our renderer never reflows an email you already wrote, and a delivery retry re-sends the identical bytes rather than deriving them again.

One Deliberate Limitation

Raw HTML inside a Markdown template is disabled. Not sanitized — off.

We're upfront about it because it's a real constraint: if you need a layout Markdown can't express, use an HTML template instead. Both formats are supported and always will be.

The reason is that sanitizing email HTML is a losing game. We measured it: running rendered email HTML through a conventional sanitizer stripped the doctype, the <style> block, the @media queries, and the Outlook conditionals — a 13.8 KB email came out at 6.9 KB with its responsiveness gone. The sanitizer worked exactly as designed and destroyed the email anyway. Turning raw HTML off at the source is both safer and better-looking.

Try It

Markdown templates are live for every workspace, on every plan, today. Create one from the dashboard, or POST your first one with the curl above.

The full syntax reference lives in the docs: Markdown templates.

If you hit a layout Markdown can't reach, the HTML editor is still right there. We're not taking anything away — we're removing the reason most people needed it.