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>
![alt](src) <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 preheader to control the preview text (otherwise clients show the first body text)
  • Test with norq preview to see the rendered email in a browser
  • Use :::fields for structured data instead of manual tables
  • Use :::table for array data that needs tabular layout
  • Put legal/unsubscribe links in :::footer for consistent bottom placement