Install
mkdir -p .claude/skills/email-template-builder && curl -L -o skill.zip "https://mcp.directory/api/skills/download/2351" && unzip -o skill.zip -d .claude/skills/email-template-builder && rm skill.zipInstalls to .claude/skills/email-template-builder
About this skill
Email Template Builder
Tier: POWERFUL
Category: Engineering Team
Domain: Transactional Email / Communications Infrastructure
Overview
Build complete transactional email systems: React Email templates, provider integration, preview server, i18n support, dark mode, spam optimization, and analytics tracking. Output production-ready code for Resend, Postmark, SendGrid, or AWS SES.
Core Capabilities
- React Email templates (welcome, verification, password reset, invoice, notification, digest)
- MJML templates for maximum email client compatibility
- Multi-provider support with unified sending interface
- Local preview server with hot reload
- i18n/localization with typed translation keys
- Dark mode support using media queries
- Spam score optimization checklist
- Open/click tracking with UTM parameters
When to Use
- Setting up transactional email for a new product
- Migrating from a legacy email system
- Adding new email types (invoice, digest, notification)
- Debugging email deliverability issues
- Implementing i18n for email templates
Project Structure
emails/
├── components/
│ ├── layout/
│ │ ├── email-layout.tsx # Base layout with brand header/footer
│ │ └── email-button.tsx # CTA button component
│ ├── partials/
│ │ ├── header.tsx
│ │ └── footer.tsx
├── templates/
│ ├── welcome.tsx
│ ├── verify-email.tsx
│ ├── password-reset.tsx
│ ├── invoice.tsx
│ ├── notification.tsx
│ └── weekly-digest.tsx
├── lib/
│ ├── send.ts # Unified send function
│ ├── providers/
│ │ ├── resend.ts
│ │ ├── postmark.ts
│ │ └── ses.ts
│ └── tracking.ts # UTM + analytics
├── i18n/
│ ├── en.ts
│ └── de.ts
└── preview/ # Dev preview server
└── server.ts
Base Email Layout
// emails/components/layout/email-layout.tsx
import {
Body, Container, Head, Html, Img, Preview, Section, Text, Hr, Font
} from "@react-email/components"
interface EmailLayoutProps {
preview: string
children: React.ReactNode
}
export function EmailLayout({ preview, children }: EmailLayoutProps) {
return (
<Html lang="en">
<Head>
<Font
fontFamily="Inter"
fallbackFontFamily="Arial"
webFont={{ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2", format: "woff2" }}
fontWeight={400}
fontStyle="normal"
/>
{/* Dark mode styles */}
<style>{`
@media (prefers-color-scheme: dark) {
.email-body { background-color: #0f0f0f !important; }
.email-container { background-color: #1a1a1a !important; }
.email-text { color: #e5e5e5 !important; }
.email-heading { color: #ffffff !important; }
.email-divider { border-color: #333333 !important; }
}
`}</style>
</Head>
<Preview>{preview}</Preview>
<Body className="email-body" style={styles.body}>
<Container className="email-container" style={styles.container}>
{/* Header */}
<Section style={styles.header}>
<Img src="https://yourapp.com/logo.png" width={120} height={40} alt="MyApp" />
</Section>
{/* Content */}
<Section style={styles.content}>
{children}
</Section>
{/* Footer */}
<Hr style={styles.divider} />
<Section style={styles.footer}>
<Text style={styles.footerText}>
MyApp Inc. · 123 Main St · San Francisco, CA 94105
</Text>
<Text style={styles.footerText}>
<a href="{{unsubscribe_url}}" style={styles.link}>Unsubscribe</a>
{" · "}
<a href="https://yourapp.com/privacy" style={styles.link}>Privacy Policy</a>
</Text>
</Section>
</Container>
</Body>
</Html>
)
}
const styles = {
body: { backgroundColor: "#f5f5f5", fontFamily: "Inter, Arial, sans-serif" },
container: { maxWidth: "600px", margin: "0 auto", backgroundColor: "#ffffff", borderRadius: "8px", overflow: "hidden" },
header: { padding: "24px 32px", borderBottom: "1px solid #e5e5e5" },
content: { padding: "32px" },
divider: { borderColor: "#e5e5e5", margin: "0 32px" },
footer: { padding: "24px 32px" },
footerText: { fontSize: "12px", color: "#6b7280", textAlign: "center" as const, margin: "4px 0" },
link: { color: "#6b7280", textDecoration: "underline" },
}
Welcome Email
// emails/templates/welcome.tsx
import { Button, Heading, Text } from "@react-email/components"
import { EmailLayout } from "../components/layout/email-layout"
interface WelcomeEmailProps {
name: "string"
confirmUrl: string
trialDays?: number
}
export function WelcomeEmail({ name, confirmUrl, trialDays = 14 }: WelcomeEmailProps) {
return (
<EmailLayout preview={`Welcome to MyApp, ${name}! Confirm your email to get started.`}>
<Heading style={styles.h1}>Welcome to MyApp, {name}!</Heading>
<Text style={styles.text}>
We're excited to have you on board. You've got {trialDays} days to explore everything MyApp has to offer — no credit card required.
</Text>
<Text style={styles.text}>
First, confirm your email address to activate your account:
</Text>
<Button href={confirmUrl} style={styles.button}>
Confirm Email Address
</Button>
<Text style={styles.hint}>
Button not working? Copy and paste this link into your browser:
<br />
<a href={confirmUrl} style={styles.link}>{confirmUrl}</a>
</Text>
<Text style={styles.text}>
Once confirmed, you can:
</Text>
<ul style={styles.list}>
<li>Connect your first project in 2 minutes</li>
<li>Invite your team (free for up to 3 members)</li>
<li>Set up Slack notifications</li>
</ul>
</EmailLayout>
)
}
export default WelcomeEmail
const styles = {
h1: { fontSize: "28px", fontWeight: "700", color: "#111827", margin: "0 0 16px" },
text: { fontSize: "16px", lineHeight: "1.6", color: "#374151", margin: "0 0 16px" },
button: { backgroundColor: "#4f46e5", color: "#ffffff", borderRadius: "6px", fontSize: "16px", fontWeight: "600", padding: "12px 24px", textDecoration: "none", display: "inline-block", margin: "8px 0 24px" },
hint: { fontSize: "13px", color: "#6b7280" },
link: { color: "#4f46e5" },
list: { fontSize: "16px", lineHeight: "1.8", color: "#374151", paddingLeft: "20px" },
}
Invoice Email
// emails/templates/invoice.tsx
import { Row, Column, Section, Heading, Text, Hr, Button } from "@react-email/components"
import { EmailLayout } from "../components/layout/email-layout"
interface InvoiceItem { description: string; amount: number }
interface InvoiceEmailProps {
name: "string"
invoiceNumber: string
invoiceDate: string
dueDate: string
items: InvoiceItem[]
total: number
currency: string
downloadUrl: string
}
export function InvoiceEmail({ name, invoiceNumber, invoiceDate, dueDate, items, total, currency = "USD", downloadUrl }: InvoiceEmailProps) {
const formatter = new Intl.NumberFormat("en-US", { style: "currency", currency })
return (
<EmailLayout preview={`Invoice ${invoiceNumber} - ${formatter.format(total / 100)}`}>
<Heading style={styles.h1}>Invoice #{invoiceNumber}</Heading>
<Text style={styles.text}>Hi {name},</Text>
<Text style={styles.text}>Here's your invoice from MyApp. Thank you for your continued support.</Text>
{/* Invoice Meta */}
<Section style={styles.metaBox}>
<Row>
<Column><Text style={styles.metaLabel}>Invoice Date</Text><Text style={styles.metaValue}>{invoiceDate}</Text></Column>
<Column><Text style={styles.metaLabel}>Due Date</Text><Text style={styles.metaValue}>{dueDate}</Text></Column>
<Column><Text style={styles.metaLabel}>Amount Due</Text><Text style={styles.metaValueLarge}>{formatter.format(total / 100)}</Text></Column>
</Row>
</Section>
{/* Line Items */}
<Section style={styles.table}>
<Row style={styles.tableHeader}>
<Column><Text style={styles.tableHeaderText}>Description</Text></Column>
<Column><Text style={{ ...styles.tableHeaderText, textAlign: "right" }}>Amount</Text></Column>
</Row>
{items.map((item, i) => (
<Row key={i} style={i % 2 === 0 ? styles.tableRowEven : styles.tableRowOdd}>
<Column><Text style={styles.tableCell}>{item.description}</Text></Column>
<Column><Text style={{ ...styles.tableCell, textAlign: "right" }}>{formatter.format(item.amount / 100)}</Text></Column>
</Row>
))}
<Hr style={styles.divider} />
<Row>
<Column><Text style={styles.totalLabel}>Total</Text></Column>
<Column><Text style={styles.totalValue}>{formatter.format(total / 100)}</Text></Column>
</Row>
</Section>
<Button href={downloadUrl} style={styles.button}>Download PDF Invoice</Button>
</EmailLayout>
)
}
export default InvoiceEmail
const styles = {
h1: { fontSize: "24px", fontWeight: "700", color: "#111827", margin: "0 0 16px" },
text: { fontSize: "15px", lineHeight: "1.6", color: "#374151", margin: "0 0 12px" },
metaBox: { backgroundColor: "#f9fafb", borderRadius: "8px", padding: "16px", margin: "16px 0" },
metaLabel: { fontSize: "12px", color: "#6b7280", fontWeight: "600", textTransform: "uppercase" as const, margin: "0 0 4px" },
metaValue: { fontSize: "14px", color: "#111827", margin: 0 },
metaValueLarge: { fontSize: "20px", fontWeight: "700", color: "#4f46e5", margin: 0 },
table: { width: "100%", margin: "16px 0" },
tableHeader: { backgroundColor: "#f3f4f6", borderRadius: "4px" },
tableHeaderText: { fontSize: "12px", fontWeight: "600", color: "#374151", padding: "8px 12px", textTransform: "uppercase" as const },
tableRowEven: { backgroundColor: "#ffffff" },
tableRowOdd: { backgroundColor: "#f9fafb" },
tableCell: { fontSize: "14px", color: "#374151", padding: "10px 12px" },
divider: { borderColor: "#e5e5e5", margin: "8px 0" },
totalLabel: { fontSize: "16px", fontWeight: "700", color: "#111827", padding: "8px 12px" },
totalValue: { fontSize: "16px", fontWeight: "700", color: "#111827", textAlign: "right" as const, padding: "8px 12px" },
button: { backgroundColor: "#4f46e5", color: "#fff", borderRadius: "6px", padding: "12px 24px", fontSize: "15px", fontWeight: "600", textDecoration: "none" },
}
Unified Send Function
// emails/lib/send.ts
import { Resend } from "resend"
import { render } from "@react-email/render"
import { WelcomeEmail } from "../templates/welcome"
import { InvoiceEmail } from "../templates/invoice"
import { addTrackingParams } from "./tracking"
const resend = new Resend(process.env.RESEND_API_KEY)
type EmailPayload =
| { type: "welcome"; props: Parameters<typeof WelcomeEmail>[0] }
| { type: "invoice"; props: Parameters<typeof InvoiceEmail>[0] }
export async function sendEmail(to: string, payload: EmailPayload) {
const templates = {
welcome: { component: WelcomeEmail, subject: "Welcome to MyApp — confirm your email" },
invoice: { component: InvoiceEmail, subject: `Invoice from MyApp` },
}
const template = templates[payload.type]
const html = render(template.component(payload.props as any))
const trackedHtml = addTrackingParams(html, { campaign: payload.type })
const result = await resend.emails.send({
from: "MyApp <hello@yourapp.com>",
to,
subject: template.subject,
html: trackedHtml,
tags: [{ name: "email-type", value: payload.type }],
})
return result
}
Preview Server Setup
// package.json scripts
{
"scripts": {
"email:dev": "email dev --dir emails/templates --port 3001",
"email:build": "email export --dir emails/templates --outDir emails/out"
}
}
// Run: npm run email:dev
// Opens: http://localhost:3001
// Shows all templates with live preview and hot reload
i18n Support
// emails/i18n/en.ts
export const en = {
welcome: {
preview: (name: "string-welcome-to-myapp-name"
heading: (name: "string-welcome-to-myapp-name"
body: (days: number) => `You've got ${days} days to explore everything.`,
cta: "Confirm Email Address",
},
}
// emails/i18n/de.ts
export const de = {
welcome: {
preview: (name: "string-willkommen-bei-myapp-name"
heading: (name: "string-willkommen-bei-myapp-name"
body: (days: number) => `Du hast ${days} Tage Zeit, alles zu erkunden.`,
cta: "E-Mail-Adresse bestätigen",
},
}
// Usage in template
import { en, de } from "../i18n"
const t = locale === "de" ? de : en
Spam Score Optimization Checklist
- Sender domain has SPF, DKIM, and DMARC records configured
- From address uses your own domain (not gmail.com/hotmail.com)
- Subject line under 50 characters, no ALL CAPS, no "FREE!!!"
- Text-to-image ratio: at least 60% text
- Plain text version included alongside HTML
- Unsubscribe link in every marketing email (CAN-SPAM, GDPR)
- No URL shorteners — use full branded links
- No red-flag words: "guarantee", "no risk", "limited time offer" in subject
- Single CTA per email — no 5 different buttons
- Image alt text on every image
- HTML validates — no broken tags
- Test with Mail-Tester.com before first send (target: 9+/10)
Analytics Tracking
// emails/lib/tracking.ts
interface TrackingParams {
campaign: string
medium?: string
source?: string
}
export function addTrackingParams(html: string, params: TrackingParams): string {
const utmString = new URLSearchParams({
utm_source: params.source ?? "email",
utm_medium: params.medium ?? "transactional",
utm_campaign: params.campaign,
}).toString()
// Add UTM params to all links in the email
return html.replace(/href="(https?:\/\/[^"]+)"/g, (match, url) => {
const separator = url.includes("?") ? "&" : "?"
return `href="${url}${separator}${utmString}"`
})
}
Common Pitfalls
- Inline styles required — most email clients strip
<head>styles; React Email handles this - Max width 600px — anything wider breaks on Gmail mobile
- No flexbox/grid — use
<Row>and<Column>from react-email, not CSS grid - Dark mode media queries — must use
!importantto override inline styles - Missing plain text — all major providers have a plain text field; always populate it
- Transactional vs marketing — use separate sending domains/IPs to protect deliverability
More by alirezarezvani
View all →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
rust-coding-skill
UtakataKyosui
Guides Claude in writing idiomatic, efficient, well-structured Rust code using proper data modeling, traits, impl organization, macros, and build-speed best practices.
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.