Claude Code skill — generate cross-client HTML email with MJML. Outlook-safe, Gmail-optimized, WCAG 2.1 AA accessible.
npx skills add https://github.com/framix-team/skill-email-html-mjml --skill email-html-mjmlCLI를 사용하여 이 스킬을 설치하고 작업 공간에서 SKILL.md 워크플로 사용을 시작하세요.
A Claude Code skill that generates responsive, cross-client HTML email from a single conversation.
Describe your email. Get back valid MJML source and compiled, production-ready HTML — guaranteed to render in Outlook 2013–365, Gmail (web and app), and Apple Mail without manual table coding, VML hand-authoring, or email client guesswork.
Every major email client uses a different rendering engine:
<head> CSS and clips messages over 102KBinline-block elementsThe result: an email that looks correct in a browser can break catastrophically in production. Fixing it requires deep knowledge of VML injection, Ghost Tables, CSS inlining, and client-specific quirks that are rarely documented in one place.
This skill uses MJML 4.x — not as a convenience layer, but as a structural reliability framework. MJML compiles semantic XML into the deeply nested, client-specific table HTML that email clients actually need. The output includes:
<mj-section> and <mj-hero>, the only two components where Outlook supports themWriting this HTML by hand is error-prone and nearly impossible to maintain. MJML makes the correct output the default output.
Every template is compiled with --config.minify=true, which removes whitespace between inline-block elements. This serves two purposes: it keeps compiled HTML under Gmail's 102KB clip threshold, and it eliminates the iOS/Android column stacking bug caused by whitespace between columns — even inside <mj-group>.
<mj-font>, which wraps @font-face imports in MSO conditional comments so Outlook ignores them and uses the system fallback stack instead of Times New Romantop, center, bottom) — pixel values are silently ignored by OutlookMulti-column layouts that must stay side-by-side on mobile (social bars, logo rows, icon grids) use <mj-group> to prevent stacking. Combined with minification, this eliminates the whitespace-triggered stacking bug across iOS Mail and Android Gmail.
The <mj-head> block is the control center for every template:
<mj-attributes> sets global defaults (<mj-all>) and named classes (<mj-class>) that eliminate repetitive inline styles across sections<mj-style inline="inline"> forces Juice CSS inlining for Gmail compatibility — critical layout styles never rely on <head> CSS alone<mj-font> imports web fonts with automatic Outlook exclusion<mj-preview> populates inbox preview textWhen dark mode support is required, the skill implements the full pattern: <meta name="color-scheme" content="light dark"> via <mj-raw>, logo swapping via inline="inline" style hiding, and @media (prefers-color-scheme: dark) overrides in non-inlined <mj-style>. Safe neutrals #121212 and #F1F1F1 replace pure black and white to prevent jarring forced inversions in Apple Mail.
<mj-image> requires alt text — enforced at generation time<mj-title> populates both <title> and the aria-label on the MJML-generated body wrapper <div role="article">lang on the root <mjml> tag flows through to the <html> element and body wrapper<mj-html-attributes> + css-class targeting — direct role attributes on <mj-text> are invalid under strict validation and are never usedDynamic template tags ({{handlebars}}, {% liquid %}, {{ jinja }}) are wrapped in <mj-raw> to protect them from the MJML parser. The compiled HTML preserves the tags intact for injection by your ESP (SendGrid, AWS SES, Postmark, etc.).
User request
│
▼
1. Gather requirements
Infer email type, brand colors, and layout from context.
Ask only for what is genuinely missing.
│
▼
2. Plan layout
Announce structure before writing code:
single-column / 2-col grid / hero+content / etc.
│
▼
3. Load component references
Read only the component files needed for this template.
│
▼
4. Generate MJML
Complete <mjml> document with full <mj-head>:
mj-attributes, mj-font, mj-title, mj-preview, mj-style
│
▼
5. Compile
npx mjml template.mjml -o dist/template.html \
--config.minify=true \
--config.validationLevel=strict
│
▼
6. Deliver both files
├── template.mjml (editable source, version-controllable)
└── dist/template.html (production HTML, send via ESP)
Output files are always delivered as a pair. The .mjml source is the editable artifact — version-controlled, templating-engine-friendly, safe to modify. The .html is the compiled production artifact — minified, table-based, ready to paste into any ESP.
MJML uses a hybrid rendering strategy sometimes called "spongy" layout:
Both are generated from the same MJML source. The developer writes <mj-section> and <mj-column> — MJML emits the correct structure for each target.
Column widths are auto-calculated from the default 600px body width:
| Columns | Auto width |
|---|---|
| 1 | 600px (100%) |
| 2 | 300px each (50%) |
| 3 | 200px each (33.33%) |
Override with explicit width on <mj-column>. Values must sum to 600px or 100%.
<mjml lang="en">
└── <mj-head>
│ ├── <mj-title>
│ ├── <mj-preview>
│ ├── <mj-font>
│ ├── <mj-attributes>
│ ├── <mj-style inline="inline"> ← Gmail-safe
│ ├── <mj-style> ← Dark mode / media queries
│ ├── <mj-html-attributes> ← ARIA roles
│ └── <mj-raw> ← Meta tags, template guards
└── <mj-body>
├── <mj-wrapper> ← Optional: shared border/bg across sections
│ └── <mj-section>
├── <mj-section> ← Row (background, padding, border)
│ ├── <mj-column> ← Column (width, vertical-align)
│ │ ├── <mj-text>
│ │ ├── <mj-image>
│ │ ├── <mj-button>
│ │ ├── <mj-divider>
│ │ ├── <mj-spacer>
│ │ └── <mj-table>
│ └── <mj-group> ← Prevents mobile stacking
│ └── <mj-column>
├── <mj-hero> ← Full-bleed hero with VML background
└── <mj-section>
└── <mj-column>
└── <mj-social>
└── <mj-social-element>
Hard constraint: <mj-section> cannot be nested inside another <mj-column>. All visual content must follow the Section → Column → Content hierarchy.
| # | Rule | Why It Matters |
|---|---|---|
| 1 | All content inside <mj-column> inside <mj-section> |
MJML validation fails otherwise |
| 2 | <mj-group> for side-by-side elements on mobile |
Prevents iOS/Android column stacking |
| 3 | <mj-font> + fallback stack for all web fonts |
Blocks Outlook's Times New Roman fallback |
| 4 | inline="inline" on <mj-style> for critical CSS |
Gmail strips <head> styles |
| 5 | Always compile with --config.minify=true |
Fixes stacking bug; stays under 102KB Gmail clip |
| 6 | alt on every image; <mj-title> always set |
WCAG 2.1 AA; screen reader compatibility |
| 7 | <mj-attributes> for global defaults |
Eliminates repetitive inline styles |
| 8 | <mj-hero> for full-bleed backgrounds |
VML generated automatically for Outlook |
| 9 | <mj-raw> for template engine tags |
Protects Handlebars/Liquid from the MJML parser |
Vertical-align consistency: If any <mj-column> in a section sets vertical-align, every column in that section must also set it explicitly. A single unset column causes inconsistent rendering.
Background image support: VML (Outlook-compatible background images) is only generated for <mj-section> and <mj-hero>. <mj-column> background images are not VML-rendered and will not show in Outlook.
Ending tags: <mj-text>, <mj-button>, <mj-table>, and <mj-raw> are ending tags — their content is raw HTML, not processed by the MJML engine. Do not nest other MJML components inside them.
Minify and < characters: With --config.minify=true, bare < characters inside ending tags cause parse errors. Wrap in <!-- htmlmin:ignore --> or escape as <.
This is a Claude Code skill. Listed on skills.sh.
Option A — npx skills (recommended)
npx skills add framix-team/skill-email-html-mjml
Requires the vercel-labs/skills CLI. Installs directly into ~/.claude/skills/ and works with Claude Code, opencode, and other compatible agents.
Option B — Clone and copy
git clone https://github.com/framix-team/skill-email-html-mjml
cp -r skill-email-html-mjml/email-html-mjml ~/.claude/skills/
Option C — Download ZIP
email-html-mjml/ folder to your skills directory:cp -r skill-email-html-mjml-main/email-html-mjml ~/.claude/skills/
Verify the install
ls ~/.claude/skills/email-html-mjml/
# Should show: SKILL.md compilation.md mjml-reference.md components/ assets/
Upload the email-html-mjml/ folder (zipped) via Settings → Capabilities → Skills → Upload skill.
Once installed, Claude will automatically invoke the skill when you ask it to create, generate, or build an HTML email template, or when you ask it to compile MJML or troubleshoot email rendering issues.
npx mjml compilation)npm install -D mjml
MJML is never installed globally (npm install -g mjml is explicitly avoided). Each project pins its own version. For new projects, pin to the latest stable MJML 4.x release:
{
"devDependencies": {
"mjml": "^4.15.3"
}
}
skill-email-html-mjml/ ← repo root (GitHub)
├── README.md ← this file
└── email-html-mjml/ ← installable skill folder
├── SKILL.md ← skill definition and workflow
├── compilation.md ← compilation workflow and error recovery
├── mjml-reference.md ← MJML architecture, validation, width math
├── components/
│ ├── head.md ← mj-attributes, mj-font, mj-style, mj-html-attributes
│ ├── layout.md ← mj-section, mj-column, mj-group, mj-wrapper
│ ├── content.md ← mj-text, mj-image, mj-button, mj-divider, mj-table
│ ├── interactive.md ← mj-social, mj-navbar, mj-accordion, mj-carousel
│ └── advanced.md ← mj-hero, mj-raw, mj-include
└── assets/
└── examples/
└── basic-layout.mjml ← MJML docs basic layout (structural reference)
Component reference files are loaded on-demand — only the files relevant to the current template are read into context. This keeps token usage minimal for simple templates while making the full reference available for complex ones.
MIT
Framix — Growth Web Presence for Scaling Companies