skills/email-designer/SKILL.md
Generate Outlook-compatible email templates (EML + HTML) through conversation. Three modes: Design (create from scratch), Import (replicate an existing .eml), Production (fill Excel data into a crystallized template). Use when user wants to: create or design an email template, generate an .eml file, make a newsletter, format an email for Outlook, import/replicate an email (导入/复刻邮件), design a 邮件模板, do 邮件排版 or 邮件设计, build pixel-perfect HTML email with Outlook compatibility. Triggers: weekly report email (周报邮件), product update email, event invitation (活动邀请邮件), announcement (公告邮件), company newsletter, .eml import, replicate email template, or make an email look professional/beautiful for Outlook. Handles visual design, EML generation, and EML import — not SMTP, sending, or account management. Without this skill, Outlook emails break because Outlook uses Word rendering which ignores modern CSS.
npx skillsauth add aiden0z/skills email-designerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
This skill has three layers:
The core (HTML + EML) uses Python stdlib only. Optional features (charts, header banners, image optimization) require additional packages that are auto-installed when needed — see Step 0.
Before starting, verify that Python 3 is available. Try these commands (use whichever works on the current platform):
python3 --version # macOS / Linux
python --version # Windows (check that output shows 3.x, not 2.x)
uname -s and uname -m (or systeminfo on Windows) to detect the user's OS and architecture.中文: Email Designer 需要 Python 3.8 或更高版本。请访问 https://www.python.org/downloads/ 下载并安装适合你操作系统的版本,安装完成后重新运行。
English: Email Designer requires Python 3.8 or later. Please visit https://www.python.org/downloads/ to download and install the version for your OS, then try again.
If Step 1 determines the email needs charts or image processing:
code-blocks/deps-checker.py → check_and_install(features)
features is ['charts'], ['images'], or ['charts', 'images']| Feature | Packages | What It Enables |
|---------|----------|-----------------|
| charts | plotly, kaleido | Bar, line, heatmap, pie chart generation |
| images | pillow | Header banner compositing, image compression |
| excel | openpyxl | Excel template generation and data loading (Production Mode) |
After environment checks pass, determine the appropriate mode based on user input and existing projects. The three modes are:
1. Import Mode — if the user provides a .eml file (or mentions importing/复刻 an
existing email):
code-blocks/eml-to-html.py → extract_from_eml(eml_path) to extract
HTML and embedded imagessave_extracted(result, output_dir) to save HTML + images with CID
references converted to relative pathscode-blocks/html-validator.py → validate(html)),
organize output via code-blocks/output-manager.py → create_project(name),
then skip to Step 3 (Preview & Adjust) with the extracted HTML as starting pointrules/production-mode.md § "Crystallization Process" and follow steps C0-C52. Production Mode — if email-projects/ directory exists with crystallized projects:
template.html and template.xlsx"检测到以下邮件模板项目:
- {project-name-1}
- {project-name-2} ... 请选择项目编号并提供 Excel 数据文件路径(如:1 /path/to/data.xlsx), 或输入 'new' 创建新邮件。"
code-blocks/deps-checker.py →
check_and_install(features=['excel']) to ensure openpyxl is available,
then read rules/production-mode.md and follow steps P0-P4new → continue with Design Mode3. Design Mode — default when no EML file provided and no existing projects (or user
chose new). Continue with Step 1 below.
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 needs clarification, use the guided interaction below to gather what you need. The goal is to make decisions easy — especially for non-technical users who may not know email design terminology.
Email design has 6 decision dimensions. The agent's job is to infer what it can from the user's request, then ask about the rest — one question at a time, always with a recommended default.
The 6 dimensions (ask in this order — earlier answers inform later defaults):
| # | Dimension | What to decide | How to handle | |---|-----------|---------------|---------------| | 1 | Purpose & Layout | Email type → determines structure | Usually inferable from request. Confirm, don't ask from scratch | | 2 | Content Modules | Which sections to include (KPI cards, charts, article list, table...) | Recommend a default set based on layout type. Let user add/remove | | 3 | Visual Style | Color scheme, design tone | Ask unless user mentioned brand/color. Offer 3-4 named presets | | 4 | Data & Assets | Has data files? Images? Logo? Need charts? | Inferable from layout type (dashboards need data). Ask to confirm | | 5 | Width | 600 / 800 / 1200px | Default based on layout (newsletters→600, reports→800). Confirm | | 6 | Content | Real content or placeholders? | Ask only if not already clear |
Interaction principles:
CRITICAL — DO NOT ask multiple questions in one message. Each message MUST ask about ONE dimension only. Listing all questions at once overwhelms the user and defeats the guided interaction purpose.
❌ BAD (dumping all questions at once): "请告诉我:1. 报告内容范围 2. 视觉风格 3. 布局偏好 4. 邮件宽度 5. 其他"
✅ GOOD (one question per message, with recommendation): Message 1: "季度商机报告 — 我推荐 Dashboard 布局(800px)。通常包含:A) KPI 指标卡 B) 趋势图表 ..." Message 2: "配色风格?A) 深蓝商务 B) ..." Message 3: "你有现成的数据吗?A) 有 B) 先用示例数据"
Infer first, confirm second. Parse everything the user already said. For "商机季度报告邮件", you already know: Dashboard layout, likely needs charts and KPI cards, 800px is appropriate. State your inference and ask for confirmation — don't present all 7 layouts and ask them to choose.
One question per message. Each message asks about one dimension. This keeps the user focused and makes it easy to answer. If a dimension is already known (inferred or stated by user), skip it entirely.
Always recommend. Every question includes a labeled recommendation with brief reasoning: "推荐 A(深蓝商务),适合正式的季度报告". Users who don't have a preference can just accept.
Multiple choice preferred. Use A/B/C/D options with short descriptions rather than open-ended questions. Include an open option for customization (e.g., "D) 自定义颜色").
3 questions maximum. If you've asked 3 questions and still have unknowns, use sensible defaults for the rest. Most users lose patience beyond 3 rounds. Combine questions only when two dimensions are tightly related (e.g., layout + width).
Example flow for "帮我做一个商机季度报告邮件":
Agent infers: Dashboard layout, 800px, needs charts/KPI.
Question 1 (confirm inference + ask modules):
"季度商机报告 — 我推荐 Dashboard 布局(800px)。这类报告通常包含: A) KPI 指标卡 B) 趋势图表 C) 漏斗图 D) 分布图 E) Top 列表 F) 总结文字 推荐:全选,季度报告信息量大。你要哪些?"
Question 2 (visual style):
"配色风格? A) 深蓝商务 B) 深绿增长 C) 紫色科技 D) 自定义颜色 推荐:A 深蓝商务,适合正式的季度报告"
Question 3 (data):
"你有现成的数据吗? A) 有,我提供数据 B) 先用示例数据,之后替换"
Then start generating — no more questions.
Using the guided interaction above, resolve these dimensions:
Layout: Check templates/layouts/ for options:
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.
After understanding layout/width/colors, assess what visual materials are needed:
If any material preparation is needed:
If no materials needed → skip directly to Step 2.
Prepare visual assets before generating HTML. All outputs go to the project's images/ directory.
rules/chart-design-system.md for visual constraintscode-blocks/chart-generator.py:
gen = EmailChartGenerator(container_width=WIDTH, output_dir='OUTPUT/images')
path = gen.bar_chart(categories=[...], series={...}, title='...', filename='chart_name.png')
images/{chart_name}.pngcode-blocks/header-generator.py:
gen = HeaderGenerator()
path = gen.generate(title='...', subtitle='...', output_path='OUTPUT/images/header_banner.jpg',
bg_image='path/to/bg.png') # or bg_color='#2563eb' for solid
images/header_banner.jpgimages/ directoryrules/design-system.md § Image filename rules)code-blocks/image-optimizer.py:
results = optimize_directory('OUTPUT/images/', threshold_kb=200)
# results = [(filename, original_kb, compressed_kb), ...]
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/chart-design-system.md — ONLY when generating charts. Color system,
typography, sizing, and data label conventions for email-embedded charts.rules/email-best-practices.md — design guidelinesrules/style-presets.md — design style presets (Corporate, Editorial, Minimal).
Choose a style matching the email's purpose to guide spacing, font sizes, and color usage.rules/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 referenceDesign 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:
rules/outlook-compatibility.md strictly — it covers table layout, inline
styles, VML dividers, spacer rows, MSO conditionals, and all other Outlook quirks.
Read that file before generating any HTML.<div style="display:none;">Preview text</div>
right after <body>.After generating:
code-blocks/html-validator.py → validate(html).
Checks 32 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.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.{project_dir}/newsletter-preview.htmlcode-blocks/preview-helper.py → open_in_browser()
ascii_layout_summary(html)Ask: "Want to fill in content now, or leave placeholders for editing in Outlook?"
If filling now:
code-blocks/content-filler.py → generate_fill_template(html) to show
all placeholders as a YAML-like template the user can fill at oncefill_batch(html, content_dict, image_dir) for efficient batch filling
(auto-maps images from a directory to CID placeholders)unfilled_placeholders(html) for any remainingIf 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 onceRe-validate after patching: html-validator.py → validate(patched_html).
This is where the HTML becomes a real email file. Two options:
Option A (recommended): Use eml-builder.py fluent API
Write a short Python script that uses the EMLBuilder class:
from pathlib import Path
# Read the eml-builder.py source, then use:
eml = (
EMLBuilder(sender="", subject="Newsletter Title")
.set_html(Path("output/newsletter-preview.html").read_text())
.add_image("logo", "output/images/logo.png") # for each CID image
.build("output/newsletter.eml")
)
Option B: Use html-to-eml.py script template
Copy the script, edit the CONFIG section at the top, then run it:
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
Both approaches use Python's built-in email module — no pip install needed. They create
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.
CRITICAL — Use the provided scripts only. You MUST use
eml-builder.py(Option A) orhtml-to-eml.py(Option B) to generate EML. DO NOT write your own temporary/inline Python script for EML generation — it will likely produce incorrect MIME structure or miss CID image embedding, resulting in broken images in Outlook.
After EML is generated, validate before proceeding:
code-blocks/eml-validator.py → validate_eml(eml_path).
Checks 14 rules including: MIME structure, text/plain fallback, CID forward
completeness (every src="cid:xxx" has a matching embedded image), residual
unresolved image paths, Content-ID format (RFC 2392), X-Unsent header,
Content-Disposition inline, and file size. Checks are adaptive — image-related
rules only fire when the HTML actually references images; pure-text emails
pass cleanly.After validation passes, you MUST proceed to Step 6 — do not end the conversation here.
Always perform all of the following, in order:
This is important — many users will want to reuse this template with different data in the future (e.g., weekly reports, periodic newsletters). Always ask:
"邮件设计完成。是否要将此模板沉淀为可复用项目?以后只需填 Excel 即可重复生成。"
If the user agrees, read rules/production-mode.md § "Crystallization Process" and follow steps C0-C5.
After crystallization completes, continue with 6b and 6c below.
If the user declines, continue with 6b and 6c below.
code-blocks/template-manager.py → save_template()EML 文件: /Users/name/project/output/2026-03-15_report/newsletter.eml
HTML 预览: /Users/name/project/output/2026-03-15_report/newsletter-preview.html
图片目录: /Users/name/project/output/2026-03-15_report/images/
Use the actual working directory path, not relative paths like output/....Display the appropriate Outlook usage guide:
templates/guides/outlook-usage-guide-zh.mdtemplates/guides/outlook-usage-guide-en.mdThis skill uses two different placeholder mechanisms for different purposes:
{{placeholder}} (Design Mode) — used by code-blocks/content-filler.py for
one-time placeholder filling during interactive design. Simple string replacement.
Use this when building emails from scratch in Design Mode.
<!-- SECTION/FIELD --> comments (Production Mode) — used in crystallized
template.html files as structural markers that the AI agent reads to understand
where to insert Excel data. These are NOT processed by content-filler.py.
See rules/production-mode.md for details.
The two systems serve different workflows and do not interact. content-filler.py is a Design Mode tool; Production Mode uses the AI agent as the rendering engine.
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)
style-presets.md ← 3 design styles: Corporate, Editorial, Minimal
placeholder-i18n.md ← Localized placeholder text (zh/en/ja)
chart-design-system.md ← Chart colors, typography, sizing (read before chart generation)
brand-color-extraction.md ← Color extraction + preset palettes
production-mode.md ← Production mode: detection, workflow, crystallization, Excel integration
templates/
components/*.html ← 19 Outlook-safe HTML building blocks
(header, section, card, table, image-placeholder,
divider, footer, stats-grid, nav-bar, status-badge,
progress-bar, button, callout, testimonial,
feature-list, pricing-table, team-member,
alert, timeline)
layouts/*.md ← 7 preset layout descriptions
(single-column, two-column, magazine, announcement,
dashboard, transactional, onboarding)
guides/*.md ← End-user Outlook usage guides (zh/en)
code-blocks/
html-validator.py ← Run AFTER generating HTML, BEFORE EML (auto-check 32 rules)
eml-validator.py ← Run AFTER generating EML, BEFORE Step 6 (auto-check 14 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 ← HTML→EML conversion (edit CONFIG section, then execute)
eml-to-html.py ← Extract HTML + images from .eml files (Import Mode)
content-filler.py ← {{placeholder}} replacement + batch filling
template-manager.py ← Save/load/list custom templates
preview-helper.py ← Browser auto-open + ASCII layout
deps-checker.py ← Auto-install optional dependencies (charts, images)
chart-generator.py ← Plotly chart generation (bar, line, heatmap, pie)
header-generator.py ← Header banner image compositing (text on background)
image-optimizer.py ← Image compression (PNG→JPEG, resize, optimize)
excel-template-generator.py ← Generate & load Excel data templates (openpyxl)
examples/
example-single-column.html ← Complete 600px single-column reference
example-two-column.html ← Complete 800px two-column reference
testing
Use when asked to review a skill's quality, test whether a skill works correctly, find why a skill behaves inconsistently or fails to trigger, check if a skill is ready to publish, harden a skill against known failure modes, or turn an observed failure into a repeatable test case.
development
Use when asked to find Bugs, audit or review a repository, scan code for security/reliability/architecture risks, inspect a folder of many repos, produce evidence-backed Bug reports, continue a prior audit, or compare/triage candidate findings.
development
Vibe Deck — vibe-code professional slide presentations — describe what you want, AI builds it. Scaffolds a React + ECharts project, creates slides with charts, animations, theming, and PDF export. Use PROACTIVELY when the user mentions slides, deck, presentation, PPT, PPTX, slideshow, keynote, pitch deck, quarterly review, board meeting, investor update, sales deck, training deck, onboarding slides, report presentation, add a slide, build a deck, create slides, make a roadmap slide, put this data into a presentation, turn this Excel into slides, visualize this data as a deck. Also trigger when the user wants to modify, reorder, or delete slides in an existing slide-kit project. Also trigger when the user wants to share, export, or package the deck as a single HTML file for email or offline viewing. Chinese triggers: 做PPT, 做个deck, 写pptx, 创建演示, 制作幻灯片, 做幻灯片, 加一页, 新增slide, 做演示文稿, 工作汇报, 述职报告, 季度回顾, 方案展示, 写个汇报, 改一下这页, 调整幻灯片顺序, 删掉这页, 把数据做成图表展示, 帮我做个路线图, 导出单个HTML, 分享给别人看.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.