Integrations
Email
MJML

MJML support

Learn how to use MJML to build responsive email layouts and templates in Knock.

Knock supports MJML, a responsive email framework that compiles to HTML that is optimized for email clients. MJML abstracts away the complexity of table-based layouts and media queries, so you can build responsive emails that look great across devices with less code.

MJML layouts

#

You can set an email layout to use MJML. When a layout is configured for MJML, it must contain a root <mjml> tag. The layout structure works the same as HTML layouts: the {{content}} variable receives the template content, and {{footer_links}} receives footer links when configured.

To include plain HTML within an MJML layout, wrap it in <mj-raw> tags. MJML will pass through the contents of <mj-raw> without compiling them, so you can use standard HTML where needed:

MJML templates

#

Email templates can use MJML in two ways:

  1. Full template. Write your entire template in MJML in the code editor. MJML templates can be used with "No layout" (standalone) or within an MJML layout.
  2. Visual block editor. Use the visual editor to compose your template. When the template or its layout is MJML, the blocks render as MJML components.

When you use an MJML template with a layout, the layout must also be MJML. When you use "No layout," the template stands alone as a complete MJML document.

Mixing HTML and MJML

#

Knock automatically wraps plain HTML inside MJML templates and layouts in <mj-raw> tags when the HTML appears at the <mj-body>, <mj-section>, or <mj-column> level. This means you can include HTML snippets in your MJML templates and they will render correctly.

Ending tags

#

Knock skips auto-wrapping of HTML when the parent element is an MJML ending tag. Ending tags are MJML components that expect plain HTML or text content as their direct children by spec.

The following MJML tags do not have their HTML children wrapped:

  • <mj-accordion-text>
  • <mj-accordion-title>
  • <mj-button>
  • <mj-navbar-link>
  • <mj-preview>
  • <mj-social-element>
  • <mj-style>
  • <mj-table>
  • <mj-text>
  • <mj-title>

Using Liquid in MJML

#

You can use Liquid in MJML layouts and templates to render dynamic content, but where you can place it is determined by the order in which Knock compiles your MJML. Knock renders an MJML email in two steps:

  1. MJML compile. Knock compiles your MJML document into HTML. Liquid is still unrendered text at this point.
  2. Liquid render. At send time, Knock renders Liquid tags and variables against the compiled HTML.

Because the MJML compiler runs first, it has to parse your document with the Liquid still in it. Liquid that sits where the compiler expects an MJML component will break compilation, and your final message may not render as expected.

Where you can use Liquid

#
LocationSupportedWhat to do
Inside <mj-body> and the components below itYesWrite Liquid directly. No wrapping needed.
Inside an <mj-raw> or <mj-style> blockYesOpen and close each Liquid tag inside the same block.
Wrapping or outside the <mjml> root tagNoBranch inside <mj-body>, or create a second layout.
Bare at the <mj-head> levelNoMove the Liquid into an <mj-raw> or <mj-style> block.
Wrapping <mj-font>, <mj-attributes>, or <mj-breakpoint>NoDeclare these without a conditional and reference them dynamically in CSS instead.

Here's an example of an email layout using Liquid in the places it's supported:

Troubleshooting

#

If a preview or email message displays raw CSS styles and <mj-*> tags as body text, this indicates an issue with MJML compilation. Check for Liquid outside the <mjml> root, a conditional straddling an <mj-head> block, or a Liquid tag wrapping a compile-time component.

Common mistakes

#

The MJML compiler has no position for content outside the root in the document it produces, so compilation fails when you add Liquid outside the <mjml> root tag. This also applies between <mjml> and its <mj-head> and <mj-body> children.

Instead, keep one <mjml> root and move the conditional inside <mj-body>:

If the two shapes differ enough that a single document can't express both, create a second layout and select it on the email step.

These MJML tags are used within <mj-head> to configure the compiler's output, which means that the limitation mentioned in the table above applies. However, you can't resolve this by simply moving these tags inside an <mj-raw> block and wrapping them with a condition there, because <mj-raw> preserves its contents without compiling them. A tag will be emitted as literal <mj-*> markup instead of being processed by the compiler.

For example, wrapping <mj-font> in a conditional to switch fonts per brand theme won't work:

When the component has a plain-HTML equivalent, write that equivalent instead and keep the conditional inside an <mj-raw> block. Here, <mj-font> becomes the <link> tag it would have generated:

Alternatively, declare both fonts unconditionally so the compiler loads each one, then pick between them at send time in an <mj-style> block:

The tradeoff to this approach is that every declared font is referenced in the final email, so recipients' email clients may load a font that the message doesn't end up using.

<mj-attributes> and <mj-breakpoint> have no plain-HTML equivalent. For those, declare them without a conditional and branch in CSS instead, similar to the second example above.

Both halves of a Liquid tag pair must sit inside the same block. When a conditional wraps only one of an MJML block's tags, compilation will fail.

Dark mode support in MJML layouts

#

MJML layouts support dark mode using the prefers-color-scheme media query. The Knock default MJML layout includes dark mode support out of the box, automatically swapping colors and images based on the user's system preference.

To add dark mode support to a custom MJML layout, include the color scheme meta tags in <mj-head> and define your dark mode styles in an <mj-style> block:

For swapping logos and icons in dark mode, see Swapping logos and icons in dark mode in the email layouts documentation.

Styling buttons in MJML layouts

#

The Knock default MJML layout styles buttons using your branding colors, with automatic dark mode support. This applies to both legacy mj-button components and visual editor buttons.

How branding colors are applied

#
  • Solid buttons use primary_color as the background and primary_color_contrast as the text color.
  • Outline buttons use a transparent background with primary_color as the text and border color.
  • Dark mode uses dark_primary_color (defaults to #FFFFFF) and dark_primary_color_contrast (defaults to #000000).

Why dark mode uses !important overrides

#

The visual editor renders button colors as static inline styles that don't change between light and dark mode. To ensure buttons remain readable on dark backgrounds, the layout uses !important in dark mode to override these inline styles. This means per-button colors from the visual editor are respected in light mode, while dark mode enforces branding-aware colors for readability.

For more details, see Styling buttons in the email layouts documentation.

Limitations

#
  • MJML layouts require the <mjml> root tag. Layouts set to MJML mode must be valid MJML documents, with a single <mjml> root and no content outside it.
  • Liquid can't wrap the <mjml> root or compile-time components. Knock compiles MJML before it renders Liquid. See Using Liquid in MJML for the placement rules.
  • Partials cannot include MJML. HTML partials must contain HTML only. When used in an MJML template, their content is automatically wrapped in <mj-raw> tags where appropriate.
New chat