email-designer
Email Designer
Generate Outlook-compatible email templates through conversation. The user describes what they want, you produce a pixel-perfect EML file that opens as a draft in Outlook.
How It Works
This skill has three layers:
- Rules — Outlook compatibility constraints you follow when generating HTML
- Templates — Pre-built components and layouts you assemble from
- Code blocks — Python scripts (stdlib only) you execute to produce EML files
Adaptive Flow
Not every request needs the full wizard. Match your approach to the user's input:
If the user's request already contains enough info (layout, colors, width, content type are clear from context), skip ahead. For example, "帮我做一个蓝色的产品更新邮件 模板,600px" already tells you: single-column, blue (#2563eb), 600px. Go straight to generating.
If the request is vague (e.g., "生成一个邮件模板"), use the wizard steps below to gather what you need — but ask efficiently, combining questions when natural.
Step 1: Understand the Request
Parse what you already know from the user's message, then fill gaps:
-
Layout: Which layout fits? Check
templates/layouts/for options:- Single Column (单栏) — product updates, announcements, weekly digests
- Two Column (双栏) — reports with sidebar data
- Magazine (杂志) — editorial with hero image and articles
- Announcement (公告) — minimal, centered, call-to-action
- Custom — user describes, you design from components
-
Width: 600px (mobile-first) / 800px (balanced) / 1200px (desktop) / custom
-
Colors: Brand image provided? Analyze it for colors (read the image with vision). Otherwise, offer presets: Blue #2563eb, Green #059669, Orange #ea580c, Purple #7c3aed, Gray #374151. (Full palettes in
rules/brand-color-extraction.md) -
Saved templates: Run
code-blocks/template-manager.py→list_templates()to check for reusable templates. If any exist, offer them first.
Step 2: Generate HTML
Before generating HTML, read these files for guidance:
rules/outlook-compatibility.md— the Outlook compatibility rules (essential)rules/design-system.md— universal design foundation (colors, typography, spacing) (this is what makes emails look professional and modern, not just compatible)rules/design-system-data-report.md— ONLY for data-heavy emails (KPI dashboards, weekly reports, status updates). Skip this for simple newsletters/announcements.rules/email-best-practices.md— design guidelinesrules/placeholder-i18n.md— use placeholders matching the user's languagetemplates/components/*.html— proven Outlook-safe component patterns (includes stats-grid, nav-bar, status-badge for advanced layouts)examples/example-*.html— complete working examples for reference
Design tip — keep headers compact: The header should feel like a navigation bar, not a hero banner. Logo + title on one line, total height around 60-70px. Avoid tall spacer rows and oversized logos in the header — save vertical space for content.
Why Outlook compatibility matters: Outlook 2007-2019 on Windows uses Microsoft
Word's rendering engine instead of a browser engine. This means most modern CSS
(flexbox, grid, border-radius, margin) is ignored or broken. The rules file contains
battle-tested patterns from a production email system that handles this correctly.
Every HTML pattern in templates/components/ has been verified to render correctly
across Outlook, Gmail, Apple Mail, and web clients.
Key principles when generating:
- Table layout only — Outlook's Word engine doesn't understand div-based layouts
- Inline styles — Outlook strips most
<style>block selectors - Dual declarations — e.g.,
bgcolor="#2563eb" style="background-color:#2563eb"because Outlook reads HTML attributes while modern clients prefer CSS - VML for dividers — CSS borders all render as black in Outlook; use VML
v:rectwith bgcolor fallback (see the divider component for the exact pattern) - Spacer rows, not margin — Outlook ignores margin; use
<tr><td height="N" style="line-height:Npx;font-size:1px;"> </td></tr> - MSO conditional comments —
<!--[if mso]>blocks for Outlook-specific fixes - Percentage widths — components use
width="100%"and inherit from parent. Control width via the parent<td style="padding:0 16px;">, not on the component itself. Never set pixel widths on component outer tables. - Text overflow protection — all text elements need
word-wrap:break-word; overflow-wrap:break-word;to prevent long content from exceeding container width, especially on large font sizes (titles, KPI numbers). - Gmail size limit — keep HTML under 102KB or Gmail clips the email with a "View entire message" link. Most users never click it.
- Preheader text — add a hidden
<div style="display:none;">Preview text</div>right after<body>. This controls what shows in the inbox preview line. - HTTPS only — all links must use
https://. Outlook and Gmail warn abouthttp://links. - Alt text on images — every
<img>needsalt="description"for accessibility and for when images are blocked by default (Outlook does this). - No HTML lists —
<ul>/<ol>render with unpredictable spacing in Outlook. Use table rows with•or numbered text in<td>cells instead. - No CSS position —
position:absolute/relative/fixedis ignored by Outlook. - No video/audio tags — use a static image with a play button linking to the URL.
- Image containers — wrap
<img>in<td style="padding:0;line-height:0;font-size:0;">to prevent Outlook from adding invisible spacing around images. - mso-padding-alt — for critical padding (section wrappers, header/footer), add
mso-padding-alt: 24px 16px;alongside regularpaddingfor Outlook safety. - Optional sections — when a section may have no content, wrap the entire block in a conditional check and include spacer rows only when the preceding section exists.
After generating:
- Validate first: execute
code-blocks/html-validator.py→validate(html). Checks 29 rules including: forbidden CSS, missing VML, column width overflow, text overflow, Gmail 102KB size limit, missing alt text, non-HTTPS links, missing preheader, elements exceeding container width. Fix any errors before proceeding. - Organize output: execute
code-blocks/output-manager.py→create_project(name)to create a timestamped directory in the user's working directory (e.g.,./output/2026-03-15_product-report/). Never write output files into the skill's own installation directory. - Save HTML to
{project_dir}/newsletter-preview.html - Auto-open in browser: execute
code-blocks/preview-helper.py→open_in_browser() - Show ASCII layout summary in conversation: →
ascii_layout_summary(html) - Ask if adjustments needed, iterate until satisfied
Step 3: Fill Content (Optional)
Ask: "Want to fill in content now, or leave placeholders for editing in Outlook?"
If filling now:
- Execute
code-blocks/content-filler.py→generate_fill_template(html)to show all placeholders as a YAML-like template the user can fill at once - Collect content — either one at a time OR as a batch dict from the user
- Execute
fill_batch(html, content_dict, image_dir)for efficient batch filling (auto-maps images from a directory to CID placeholders) - Re-preview and check
unfilled_placeholders(html)for any remaining
Quick Edits (anytime after Step 2)
If the user asks for a targeted change (e.g., "change the header color to red",
"make the title bigger"), use code-blocks/html-patcher.py instead of regenerating:
replace_color(html, old, new)— swap a color everywherechange_width(html, old_w, new_w)— resize the containerreplace_text(html, old, new)— change visible textadd_section(html, section_html)— insert before footerpatch_file(path, colors={...}, texts={...})— apply multiple patches at once
Re-validate after patching: html-validator.py → validate(patched_html).
Step 4: Generate EML
This is where the HTML becomes a real email file. Execute code-blocks/html-to-eml.py:
# How to execute: write a modified copy of the script with filled-in CONFIG values,
# then run it with: python3 /path/to/modified_script.py
# The CONFIG section to modify:
HTML_FILE = "output/newsletter-preview.html" # your generated HTML
OUTPUT_EML = "output/newsletter.eml" # output path
SUBJECT = "..." # ask user
SENDER = "" # optional
TO_ADDRS = [] # optional
IMAGE_DIR = "output/images" # if images exist
The script uses Python's built-in email module — no pip install needed. It creates
a proper MIME structure (multipart/alternative → text/plain + multipart/related →
text/html + CID images) with X-Unsent: 1 so Outlook opens it in draft/compose mode.
Step 5: Wrap Up
- Offer to save the template: execute
code-blocks/template-manager.py→save_template() - Show the output file locations
- Display the appropriate usage guide:
- Chinese user →
templates/guides/outlook-usage-guide-zh.md - English user →
templates/guides/outlook-usage-guide-en.md
- Chinese user →
File Map
rules/
outlook-compatibility.md ← Read before generating HTML (Outlook rendering rules)
design-system.md ← Universal: colors, typography, spacing (ALWAYS read)
design-system-data-report.md ← Extension: KPI cards, status badges, trends (data emails only)
email-best-practices.md ← Design guidance (widths, colors, typography)
placeholder-i18n.md ← Localized placeholder text (zh/en/ja)
brand-color-extraction.md ← Color extraction + preset palettes
templates/
components/*.html ← 13 Outlook-safe HTML building blocks
(header, section, card, table, image-placeholder,
divider, footer, stats-grid, nav-bar, status-badge,
progress-bar, button, callout)
layouts/*.md ← 4 preset layout descriptions
guides/*.md ← End-user Outlook usage guides (zh/en)
code-blocks/
html-validator.py ← Run AFTER generating, BEFORE EML (auto-check rules)
html-patcher.py ← Targeted edits (color, width, text) without regenerating
output-manager.py ← Timestamped project directories for organized output
eml-builder.py ← EML builder class (fluent API)
cid-embedder.py ← Image scanning + placeholder PNG creation
html-to-eml.py ← Complete HTML→EML script (execute this)
content-filler.py ← {{placeholder}} replacement + batch filling
template-manager.py ← Save/load/list custom templates
preview-helper.py ← Browser auto-open + ASCII layout
examples/
example-single-column.html ← Complete 600px single-column reference
example-two-column.html ← Complete 800px two-column reference