Email Channel
Norq compiles email templates from Markdown to responsive HTML email via MJML (a responsive email markup language). The output is Outlook-safe, mobile-responsive, and includes a plain-text fallback.
Pipeline: Markdown -> AST (parse tree) -> MJML -> HTML + plain text
Template file
email.md -- always Markdown mode. Native JSON is not supported for email (HTML rendering is the core reason Norq exists).
Frontmatter
Frontmatter is YAML metadata at the top of the template, enclosed in --- markers.
---
subject: "Order #{{order.id}} has shipped!"
preheader: "Your order is on its way"
enabled: true
---| Field | Required | Description |
|---|---|---|
subject |
Yes | Email subject line. Supports {{expressions}}. |
preheader |
No | Preview text shown in inbox clients (Gmail, Outlook). |
enabled |
No | true (default) or false. Disables the channel. |
Directive compilation
| Directive | Email output |
|---|---|
:::header |
Background-colored mj-section with centered text |
:::footer |
mj-section with small font (12px, #666666) |
:::action |
mj-button elements with href and styling |
:::callout |
mj-section with background color (#fff3cd) |
:::hero |
mj-image (full-width) |
:::fields |
HTML table with bold keys |
:::media |
mj-image for images; <a> link for video/file |
:::columns |
mj-section > mj-column (native multi-column) |
:::list |
HTML <ul> or <ol> inside mj-text |
:::highlight |
Dark card -- mj-column with brandColor bg, white text, 600 weight, 8px radius |
:::centered |
mj-text with align="center" |
:::raw |
mj-raw passthrough -- content must be a fenced code block with HTML |
Components prefixed with mj- are MJML tags that compile to responsive HTML table layouts.
Example
---
subject: "Order #{{order.id}} has shipped!"
preheader: "Your order is on its way"
---
::: header
Order Shipped
:::
Hey {{user.first_name}},
Your order **#{{order.id}}** has shipped and is on its way!
::: fields
Tracking ID: {{order.tracking_id}}
Estimated delivery: {{order.delivery_date}}
:::
::: action
[Track Order]({{tracking_url}}){primary}
:::
::: if order.gift_message
> {{order.gift_message}}
:::
::: footer
[Unsubscribe]({{unsubscribe_url}})
:::Highlight
Dark card with brandColor background and white text. Use for announcements or special offers.
::: highlight
Limited-time offer: 50% off all plans!
:::Compiles to an mj-column with background-color set to brandColor (#18181b by default), color: #ffffff, font-weight: 600, and border-radius: 8px. Override colors with params: ::: highlight bg=#1e40af color=#f0f0f0.
Centered
Center-aligned text block.
::: centered
Thank you for being a customer.
:::Compiles to mj-text with align="center". Override text color with params: ::: centered color=#666666.
Compiled output
Norq produces three fields:
subject: The rendered subject line (expressions resolved)html: Responsive HTML email (MJML compiled)text: Plain-text fallback (auto-generated from Markdown)
Auto-escaping
All {{expressions}} in email templates are HTML-escaped: <, >, &, " become their HTML entity equivalents. Use {{{triple-curly}}} to output raw HTML (the linter warns about this).
Inline formatting
Standard Markdown inline formatting maps to HTML:
| Markdown | HTML |
|---|---|
**bold** |
<strong>bold</strong> |
*italic* |
<em>italic</em> |
~~strikethrough~~ |
<s>strikethrough</s> |
`code` |
<code>code</code> |
[link](url) |
<a href="url">link</a> |
 |
<img src="src" alt="alt"> (via mj-image) |
Directive parameters
All content directives accept optional parameters after the directive name on the same line.
Alignment (center, left, right):
::: hero center
https://example.com/banner.png
:::Density (compact, spacious) -- controls vertical padding:
::: fields compact
Name: {{user.name}}
:::Style overrides (bg=, color=) -- override background and text colors:
::: highlight bg=#1e40af color=#f0f0f0
Special offer just for you.
:::
::: centered color=#666666
Thank you for being a customer.
:::Parameters can be combined: ::: highlight bg=#1e40af compact.
Expression interpolation in directive params
Directive parameter values support {{expression}} interpolation:
::: hero {{hero_image_url}}
:::
::: action
[Shop Now]({{cta_url}}){primary}
:::This allows dynamic URLs and values driven by template data.
Table directive
:::table renders an iterable array as a structured table. Rows are templated with a row variable:
::: table order.items
| Item | Qty | Price |
|------|-----|-------|
| {{row.name}} | {{row.qty}} | {{row.price}} |
:::The directive iterates over the array at the given path and renders each row using the inner template. Compiles to an HTML table inside mj-text.
Variable pipe arguments
Pipes can accept variable references as arguments (in addition to literal values):
Total: {{item.cost | multiply item.qty}}This multiplies item.cost by item.qty at render time. The argument is resolved as a variable path from the template data, not a string literal.
Pipes in frontmatter subjects
The subject frontmatter field supports the full expression syntax including pipes:
---
subject: "Your order of {{item.count | pluralize "item" "items"}} is ready"
---All pipes available in the template body are also available in frontmatter string fields.
Best practices
- Keep subject lines under 60 characters for mobile display
- Use
preheaderto control the preview text (otherwise clients show the first body text) - Test with
norq previewto see the rendered email in a browser - Use
:::fieldsfor structured data instead of manual tables - Use
:::tablefor array data that needs tabular layout - Put legal/unsubscribe links in
:::footerfor consistent bottom placement