Frontmatter
Override theme values and set metadata per-email using YAML frontmatter.
Add a YAML frontmatter block at the top of your markdown to override theme values and set metadata per-email:
---
preheader: "Don't miss our biggest sale"
brand_color: "#e11d48"
button_color: "#059669"
---
# Sale Starts Now
Everything is 50% off this weekend.
::: footer
**Acme Corp** · [Unsubscribe](https://example.com/unsub)
:::Frontmatter uses snake_case keys. They map directly to the same theme options available in the JS API (which uses camelCase).
Preheader
The preheader field sets the preview text that email clients show in the inbox list next to the subject line. It's hidden in the email body itself:
---
preheader: "Your order has shipped. Track it now"
---Selecting a Theme
Use theme to switch the base theme for a single email. Individual overrides still layer on top:
---
theme: dark
brand_color: "#e11d48"
---
# Dark email with a custom brand colorValid values: light (default), dark, auto.
Automatic Dark Mode
theme: dark renders the email dark for everyone. theme: auto renders light by default but adapts to readers whose mail client is in dark mode:
---
theme: auto
---To tune the dark variant, override parts of the built-in dark palette with a dark: map (same snake_case keys as the light theme). A dark: map on its own implies theme: auto:
---
theme: auto
dark:
background_color: "#111827"
content_color: "#1f2937"
---Explicitly pinning theme: light or theme: dark renders static: it overrides the darkTheme render option when the sending app enables dark mode globally. See Theme → Automatic Dark Mode for client support notes.
Custom Fonts
Embed custom web fonts (e.g. Google Fonts) with a nested fonts: map. Each entry is a family name → stylesheet URL, rendered as a <mj-font> tag so the font loads in clients that support embedded web fonts (Apple Mail, iOS Mail):
---
fonts:
Inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
Merriweather: "https://fonts.googleapis.com/css2?family=Merriweather"
font_family: "Inter, sans-serif"
---
# HelloThe font still needs to be named in font_family (or via fontFamily in code) to actually apply to text. MJML only injects a <link> for fonts referenced in the compiled CSS, so unused entries are silently dropped.
When both the fonts: frontmatter and the fonts render option are provided, frontmatter wins on matching family names and non-overlapping entries merge together.
Language and Direction
Set lang (a language tag like en, de, or pt-BR) and dir (ltr, rtl, or auto) to emit the matching attributes on the output document's <html> tag, so screen readers pick the right voice and right-to-left scripts lay out correctly:
---
lang: ar
dir: rtl
---
# مرحباWhen unset, the output uses MJML's defaults (lang="und" dir="auto").
dir: rtl does more than set the attribute: the default text alignment flips to right (email clients don't do this for you; MJML hardcodes left alignment), and left-anchored details like blockquote bars and list indents flip with it. Explicit alignment parameters (center, left, right on directives and images) still apply as written.
Hard Line Breaks
By default, a single newline does not break a line (standard markdown; use a blank line for a new paragraph). Set breaks: true to render every newline as a line break, the way non-technical writers usually expect:
---
breaks: true
---
Line one
Line two renders below itApps can set this globally with the breaks render option; the frontmatter value wins per document.
All Frontmatter Keys
| Key | Description |
|---|---|
preheader | Inbox preview text (hidden in email body) |
theme | Appearance: light, dark, or auto (adapts to the reader's dark mode) |
brand_color | Links, highlights, accents |
heading_color | Heading text color |
body_color | Body text color |
background_color | Outer background color |
content_color | Content area background |
card_color | Callout / code block background |
button_color | Primary button background |
button_text_color | Button text color |
secondary_color | Secondary button border |
secondary_text_color | Secondary button text |
success_color | Success button background |
success_text_color | Success button text |
danger_color | Danger button background |
danger_text_color | Danger button text |
warning_color | Warning button background |
warning_text_color | Warning button text |
divider_color | Horizontal rule (---) color |
font_family | Font stack |
font_size | Base font size |
line_height | Base line height |
content_width | Email content width |
border_radius | Border radius for buttons, callouts, highlights |
fonts | Nested map of custom web fonts: family name → stylesheet URL |
dark | Map of dark-palette overrides for theme: auto (implies auto when present) |
lang | Document language tag (e.g. en, pt-BR) for the output <html> |
dir | Text direction: ltr, rtl, or auto |
breaks | true renders single newlines as line breaks |
Frontmatter values are validated before rendering: theme values containing markup characters fall back to the base theme, font entries with unsafe URLs are skipped, and the preheader is HTML-escaped in the output. Invalid values never break the render; they surface on warnings instead.
Custom Metadata
Any keys beyond the ones above are passed through in the meta object returned by render(). This is useful for storing email metadata alongside the template:
---
preheader: "Welcome aboard"
subject: "Welcome to Acme"
campaign_id: "onboarding-v2"
---
# Welcome!const { html, text, meta } = await render(markdown);
console.log(meta.subject); // "Welcome to Acme"
console.log(meta.campaign_id); // "onboarding-v2"
console.log(meta.preheader); // "Welcome aboard"