All playbooks
Playbook 3 of 6
Author templates as markdown
Templates live in your repo as markdown with YAML frontmatter. One HTML layout puts your brand on everything, and Liquid variables fill in the rest. Writing email becomes writing markdown.
≈ 15 min You ship: A templates/ directory with one markdown file per message and a branded layout in layouts.yml.
1
Create your brand layout
The layout is the HTML shell around every email: logo, colors, footer, unsubscribe link. Your templates stay pure markdown because the layout owns all the HTML.
01 · brand layout
Create a file templates/layouts.yml in this repo. It defines the branded HTML shells that wrap every markdown email we send through Messy.
Format: a YAML list where each entry has name, body, and optionally transformers.
- body is a complete HTML email document: table-based, MSO-conditional-comment compatible, inline CSS only for anything critical, max content width 600px, our logo in the header, and a footer with our company name, address and an unsubscribe link pointing at {{ unsubscribe_url }}.
- Two Liquid placeholders are required inside body: {{ content }} where the rendered message body is injected, and {{ preview }} in a hidden preheader div right after the opening body tag.
- Optionally add a transformers map controlling how markdown elements render to HTML. Keys: heading, paragraph, link, image, strong, em, list, listitem, blockquote, hr, codespan. Values are HTML snippets with placeholders like {{text}}, {{href}}, {{src}}, {{level}}. Use it to give links our brand color and paragraphs a consistent font stack, since email clients ignore stylesheets.
Look at this app's existing branding (logo assets, primary color, font) and use it. Name the layout "<AppName> Default". Create one layout only; more can come later.2
Generate the template files
With the inventory from the previous playbook and the layout in place, your agent can write every template in one pass. Review them like any other PR: the copy is right there in the diff.
02 · write the templates
Generate the Messy template files for every message in docs/messy-messages.md.
Rules for each file:
- Location: templates/<area>/<trigger>.<channel>.md, where <area> groups related messages (auth/, billing/, orders/). The directory path becomes the folder tree in Messy.
- Format: YAML frontmatter between --- lines, then the markdown body.
- Frontmatter fields: trigger (exactly as inventoried), channel, name (a human label for the dashboard), and for email also layout ("<AppName> Default"), subject and preview. Quote any frontmatter value containing Liquid, like subject: "Your code: {{ otp_code }}".
- Body: markdown with Liquid {{ variable }} interpolation, using exactly the variables from the inventory. Write real copy in this product's voice: short sentences, no filler, one clear call to action. Links as normal markdown links.
- Push templates: no layout, no subject; the body is the plain notification text.
- Do not put an unsubscribe link in template bodies; the layout footer already carries {{ unsubscribe_url }}.
One template per file. Closely related templates may share a file separated by a line containing only ===, but prefer one per file.3
What a template looks like
A finished template is small enough to read in full. Subject and preview accept Liquid too, which is why they are quoted in the frontmatter.
templates/auth/login.otp.email.md
---
layout: Acme Default
channel: email
trigger: login.otp
name: Login verification code
subject: "Your Acme code: {{ otp_code }}"
preview: "Use this code to sign in"
---
# Your login code, {{ name }}
Use the code below to sign in to your Acme account:
**{{ otp_code }}**
This code expires in 3 minutes. If you didn't request it,
you can safely ignore this email.