AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Mjml

skill-jayoram-mjml-ai-knowledge-mjml · by JayOram

Author, compile, debug, and refactor MJML (Mailjet Markup Language) responsive email templates. Use this skill whenever the user is working with MJML — writing or editing .mjml files, building or fixing a responsive HTML email, using mj-* tags (mj-section, mj-column, mj-button, mj-hero, etc.), compiling MJML to HTML via the CLI or the mjml2html Node API, setting up shared partials with mj-include…

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-jayoram-mjml-ai-knowledge-mjml

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-jayoram-mjml-ai-knowledge-mjml)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Mjml? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

MJML

MJML compiles a small set of semantic tags into responsive, client-compatible HTML email. You write `/` instead of nested tables and bulletproof-button hacks; the engine emits the ugly, well-tested HTML. The whole value proposition is that you stay at the layout level and never hand-write the table soup.

This skill assumes MJML 5 (the current major). Where v5 changed behavior from v4, it is called out — those changes are the most common source of "it worked before and now it doesn't."

The mental model (internalize this first)

An MJML document is a strict, shallow hierarchy. Every tag has exactly one valid parent context, and most rendering bugs are a tag in the wrong slot.

mjml
├── mj-head        (optional: metadata, fonts, styles, default attributes)
└── mj-body        (width=600px by default)
    └── mj-wrapper (optional: groups multiple sections, e.g. a bordered card)
        └── mj-section          (a row)
            ├── mj-column        (a responsive cell — stacks on mobile)
            │   └── content      (mj-text, mj-image, mj-button, mj-divider, …)
            └── mj-group         (keeps columns side-by-side on mobile)
                └── mj-column

Five rules cover almost everything:

  1. Content lives in columns, never directly in a section. mj-text, mj-image, mj-button etc. must sit inside an mj-column. A single-column row still needs the column.
  2. Columns live in sections. mj-column outside an mj-section is ignored.
  3. Sections don't nest, and columns don't nest. You cannot put an mj-section inside an mj-column, or an mj-column inside an mj-column. To get nested-looking layouts, use mj-wrapper (to stack sections) or mj-group (to keep columns together). This is the single most common structural mistake.
  4. Column widths in a section must sum to ≤ the section width (≤100%). With no explicit width, the section splits evenly across its columns (2 columns → 50% each, 3 → 33%, 4 → 25%). Any component inside a column is 100% of that column's width — columns are containers, not offset/spacer tools.
  5. Columns inside an mj-group must use percentage widths, not pixels. Pixel widths break grouping.

Canonical starter template

When the user wants a fresh template, start from this and build outward. It is valid, accessible, and exercises the head/body split.


  
    Newsletter
    One-line inbox preview text
    
      
      
      
    
    
      .link-light a { color: #1a73e8 !important; }
    
  
  
    
      
        
        
        Hello World
        Body copy goes here.
        Read more
      
    
  

Ending tags (why you can't nest MJML in some places)

Some components are ending tags: they may contain raw HTML but not other MJML components. The set is mj-text, mj-button, mj-table, mj-raw, mj-social-element, mj-navbar-link, mj-accordion-title, mj-accordion-text, and mj-carousel-image.

Practical consequence: rich text formatting goes inside mj-text as ordinary HTML (`, , , , inline style), not as more mj-* tags. Putting an mj-button inside an mj-text will not work — close the text and add a sibling mj-button` in the same column.


  Title
  A paragraph with a link.

Sibling button, not nested

Styling and default attributes (DRY templates)

Set defaults once in mj-head rather than repeating attributes on every tag. The cascade, highest priority first: inline attribute on the tag → matching component tag inside mj-attributesmj-all → MJML built-in default.

  • mj-attributes > ` overrides the default for *every* mj-text`.
  • mj-attributes > `` sets a default for all components.
  • mj-attributes > ` defines a reusable group applied with mj-class="big" (space-separate to combine: mj-class="big brand"`).
  • mj-style holds real CSS for the `; add inline="inline" to inline it (needed for properties many clients strip from ). Because one MJML tag emits several HTML tags, css-class` lands on the outermost element — inspect the compiled HTML to find the right child selector.

Components at a glance

Reach for references/components.md for the full attribute tables. Quick index of what each tag is for:

Layout: mj-wrapper (stack sections as a unit), mj-section (row; full-width="full-width" makes the background span edge-to-edge while content stays 600px), mj-column (responsive cell), mj-group (lock columns side-by-side on mobile).

Content: mj-text, mj-image (responsive `; omit width to fill the column), mj-button (bulletproof CTA), mj-divider, mj-spacer (vertical gap), mj-table (raw HTML table for data), mj-social + mj-social-element (share rows), mj-hero (background-image banner; background-width/background-height are mandatory), mj-accordion (collapsible, Apple-Mail-only interactivity), mj-carousel (image gallery, limited client support), mj-navbar + mj-navbar-link (menu, optional hamburger on Apple Mail), mj-raw` (escape hatch for arbitrary HTML).

Head: mj-title, mj-preview, mj-attributes, mj-style, mj-font (import a hosted @font-face CSS, only injected if used), mj-breakpoint (set the desktop↔mobile switch width), mj-html-attributes (inject attributes onto generated HTML via CSS selectors), mj-include (partials — see below).

Shared partials with mj-include (changed in v5)

mj-include pulls in external .mjml, .css (type="css", optionally css-inline="inline"), or .html (type="html") files. In MJML 5, includes are disabled by default and silently ignored. If included content is missing from the output, the includes are off, not broken.

  • CLI: add --config.allowIncludes true.
  • Node: pass ignoreIncludes: false.
  • Scope which folders are allowed with includePath (string or array), resolved against filePath. Absolute paths and .. escapes outside the allowed roots are rejected. Set filePath to your templates root and write base-relative includes (./_common/header.mjml), or keep template-relative paths and allowlist sibling folders.

  
    
    
    
  

Compiling MJML → HTML

CLI (from npm install mjml):

mjml input.mjml -o output.html          # write to file
mjml input.mjml -s                       # write to stdout
mjml -w input.mjml                        # watch a file or folder
mjml input.mjml -o out.html --config.validationLevel strict --config.minify true

Useful --config.* flags: allowIncludes, beautify (default true in CLI), minify (default false), minifyOptions ({"minifyCss": false | "lite" | "default" | }minifyCss replaced the old minifyCSS key in v5, though the old key still maps through), validationLevel (strict | soft | skip), includePath, filePath.

Node APImjml2html(input, options) returns { html, errors }:

import mjml2html from 'mjml'

const { html, errors } = await mjml2html(mjmlSource, {
  validationLevel: 'soft',     // 'strict' throws on invalid markup
  minify: false,
  ignoreIncludes: false,       // enable mj-include
  filePath: '/project/templates/email.mjml',
  includePath: ['/project/templates/_common'],
})

Always surface errors to the user when compiling programmatically — they pinpoint the offending tag and line. There is also a hosted MJML API (mjml.io/api) for environments that can't run Node.

Validation levels

The validator catches misplaced tags, unknown attributes, and broken structure before they become silently wrong HTML.

  • strict — abort on any validation error. Best for CI and when generating templates you can't eyeball.
  • soft (default) — collect errors but still produce output.
  • skip — no validation (fastest; use only when you trust the input).

When writing or transforming MJML for someone, prefer compiling with strict (or at least reading the errors array) so structural mistakes surface immediately rather than rendering as a collapsed or duplicated layout.

High-value gotchas

These are the things that waste the most time, drawn from real client-rendering behavior:

  • Outlook backgrounds. On mj-section/mj-hero, if background-size is omitted, no-repeat is ignored in Outlook; a single percentage background-size makes the image shrink-to-fit rather than crop. Always set background-size, background-position, and background-repeat explicitly when a section has a background image.
  • mj-button is not fully clickable. Only the text/inner area is the link, due to client support — don't promise an edge-to-edge tap target. For a true full-bleed clickable block, wrap an mj-image (or the whole column content) in an href instead.
  • mj-hero requires background-width and background-height, and height is required only in mode="fixed-height". Provide a background-color fallback for clients that drop the image.
  • Templating languages (Handlebars/Liquid/AMPscript) + minify. A ``.
  • Reverse column order without breaking mobile stacking. Author columns in mobile (stacked) order, then add direction="rtl" to the mj-section to flip the desktop order.
  • Self-hosted Outlook.com / media-query-less clients. owa="desktop" on the mjml tag forces the desktop layout for those clients.
  • Social icons. mj-social-element name="facebook" is a convenience that pulls Mailjet-hosted icons; for production, supply your own src rather than depending on those assets. Append -noshare to a network name to stop MJML rewriting your href into a share URL.

Working approach

When the user hands you MJML to fix, first locate the structural error against the five rules and the ending-tag list before touching styling — a "broken" email is far more often a column in the wrong place than a bad attribute. When building from scratch, sketch the section/column skeleton first, get it compiling clean under strict, then layer in content and head-level defaults. When the deliverable is the email itself, compile it and report the errors array rather than assuming the source is correct.

For exhaustive per-component attributes, defaults, and supported social networks, read references/components.md.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.