← 返回 Skills 市场
alirezarezvani

email-template-builder

作者 Alireza Rezvani · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
596
总下载
0
收藏
6
当前安装
2
版本数
在 OpenClaw 中安装
/install email-template-builder
功能描述
Email Template Builder
使用说明 (SKILL.md)

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 (
    \x3CHtml lang="en">
      \x3CHead>
        \x3CFont
          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 */}
        \x3Cstyle>{`
          @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; }
          }
        `}\x3C/style>
      \x3C/Head>
      \x3CPreview>{preview}\x3C/Preview>
      \x3CBody className="email-body" style={styles.body}>
        \x3CContainer className="email-container" style={styles.container}>
          {/* Header */}
          \x3CSection style={styles.header}>
            \x3CImg src="https://yourapp.com/logo.png" width={120} height={40} alt="MyApp" />
          \x3C/Section>
          
          {/* Content */}
          \x3CSection style={styles.content}>
            {children}
          \x3C/Section>
          
          {/* Footer */}
          \x3CHr style={styles.divider} />
          \x3CSection style={styles.footer}>
            \x3CText style={styles.footerText}>
              MyApp Inc. · 123 Main St · San Francisco, CA 94105
            \x3C/Text>
            \x3CText style={styles.footerText}>
              \x3Ca href="{{unsubscribe_url}}" style={styles.link}>Unsubscribe\x3C/a>
              {" · "}
              \x3Ca href="https://yourapp.com/privacy" style={styles.link}>Privacy Policy\x3C/a>
            \x3C/Text>
          \x3C/Section>
        \x3C/Container>
      \x3C/Body>
    \x3C/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 (
    \x3CEmailLayout preview={`Welcome to MyApp, ${name}! Confirm your email to get started.`}>
      \x3CHeading style={styles.h1}>Welcome to MyApp, {name}!\x3C/Heading>
      \x3CText 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.
      \x3C/Text>
      \x3CText style={styles.text}>
        First, confirm your email address to activate your account:
      \x3C/Text>
      \x3CButton href={confirmUrl} style={styles.button}>
        Confirm Email Address
      \x3C/Button>
      \x3CText style={styles.hint}>
        Button not working? Copy and paste this link into your browser:
        \x3Cbr />
        \x3Ca href={confirmUrl} style={styles.link}>{confirmUrl}\x3C/a>
      \x3C/Text>
      \x3CText style={styles.text}>
        Once confirmed, you can:
      \x3C/Text>
      \x3Cul style={styles.list}>
        \x3Cli>Connect your first project in 2 minutes\x3C/li>
        \x3Cli>Invite your team (free for up to 3 members)\x3C/li>
        \x3Cli>Set up Slack notifications\x3C/li>
      \x3C/ul>
    \x3C/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 (
    \x3CEmailLayout preview={`Invoice ${invoiceNumber} - ${formatter.format(total / 100)}`}>
      \x3CHeading style={styles.h1}>Invoice #{invoiceNumber}\x3C/Heading>
      \x3CText style={styles.text}>Hi {name},\x3C/Text>
      \x3CText style={styles.text}>Here's your invoice from MyApp. Thank you for your continued support.\x3C/Text>

      {/* Invoice Meta */}
      \x3CSection style={styles.metaBox}>
        \x3CRow>
          \x3CColumn>\x3CText style={styles.metaLabel}>Invoice Date\x3C/Text>\x3CText style={styles.metaValue}>{invoiceDate}\x3C/Text>\x3C/Column>
          \x3CColumn>\x3CText style={styles.metaLabel}>Due Date\x3C/Text>\x3CText style={styles.metaValue}>{dueDate}\x3C/Text>\x3C/Column>
          \x3CColumn>\x3CText style={styles.metaLabel}>Amount Due\x3C/Text>\x3CText style={styles.metaValueLarge}>{formatter.format(total / 100)}\x3C/Text>\x3C/Column>
        \x3C/Row>
      \x3C/Section>

      {/* Line Items */}
      \x3CSection style={styles.table}>
        \x3CRow style={styles.tableHeader}>
          \x3CColumn>\x3CText style={styles.tableHeaderText}>Description\x3C/Text>\x3C/Column>
          \x3CColumn>\x3CText style={{ ...styles.tableHeaderText, textAlign: "right" }}>Amount\x3C/Text>\x3C/Column>
        \x3C/Row>
        {items.map((item, i) => (
          \x3CRow key={i} style={i % 2 === 0 ? styles.tableRowEven : styles.tableRowOdd}>
            \x3CColumn>\x3CText style={styles.tableCell}>{item.description}\x3C/Text>\x3C/Column>
            \x3CColumn>\x3CText style={{ ...styles.tableCell, textAlign: "right" }}>{formatter.format(item.amount / 100)}\x3C/Text>\x3C/Column>
          \x3C/Row>
        ))}
        \x3CHr style={styles.divider} />
        \x3CRow>
          \x3CColumn>\x3CText style={styles.totalLabel}>Total\x3C/Text>\x3C/Column>
          \x3CColumn>\x3CText style={styles.totalValue}>{formatter.format(total / 100)}\x3C/Text>\x3C/Column>
        \x3C/Row>
      \x3C/Section>

      \x3CButton href={downloadUrl} style={styles.button}>Download PDF Invoice\x3C/Button>
    \x3C/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\x3Ctypeof WelcomeEmail>[0] }
  | { type: "invoice"; props: Parameters\x3Ctypeof 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 \[email protected]>",
    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 \x3Chead> styles; React Email handles this
  • Max width 600px — anything wider breaks on Gmail mobile
  • No flexbox/grid — use \x3CRow> and \x3CColumn> from react-email, not CSS grid
  • Dark mode media queries — must use !important to 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
安全使用建议
This skill appears to be a templates-and-code generator only. Before using it: review any generated code for hardcoded URLs or tracking pixels, avoid pasting production API keys into example files, supply provider credentials (Resend/Postmark/SendGrid/AWS SES) via your own project environment variables or secret store, and verify unsubscribe/analytics handling meets your privacy and deliverability requirements. If the skill ever asks for your cloud or email provider credentials, or instructs the agent to read local files or upload data to an external server, stop and re-evaluate — that would be unexpected for a template generator.
功能分析
Type: OpenClaw Skill Name: email-template-builder Version: 1.0.0 The email-template-builder skill is a legitimate utility for creating transactional email systems using React Email. It provides well-structured templates (welcome, invoice), a unified sending interface using the Resend API, and helper functions for UTM tracking and i18n. The code follows standard practices for email development and contains no indicators of malicious intent or data exfiltration.
能力评估
Purpose & Capability
The name/description (email template builder) match the SKILL.md content: templates, layout, provider adapter examples, preview server, i18n, dark mode and tracking. Nothing in the metadata or SKILL.md asks for unrelated system access or credentials.
Instruction Scope
The SKILL.md provides project scaffolding and code examples (React Email, MJML, preview server, provider adapter stubs). It references external assets (web font URL, logo URL) and placeholders like {{unsubscribe_url}} and describes adding open/click tracking and UTM parameters. The instructions do not tell the agent to read user files, environment variables, or transmit secrets, but generated code will need user-supplied provider credentials at deployment time — the document does not auto-provision those.
Install Mechanism
No install spec and no code files are included; this is instruction-only. Nothing is downloaded or executed by the skill itself.
Credentials
The skill declares no required environment variables or credentials. That is proportionate for a code/template generator. (Note: real sending integrations will require provider API keys that the user must supply when they implement/deploy the generated code.)
Persistence & Privilege
The skill is not always-enabled and does not request persistent or cross-skill configuration. It does not attempt to modify other skills or system settings.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install email-template-builder
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /email-template-builder 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial publish
v2.1.1
v2.1.1: optimization, reference splits
元数据
Slug email-template-builder
版本 1.0.0
许可证 MIT-0
累计安装 6
当前安装数 6
历史版本数 2
常见问题

email-template-builder 是什么?

Email Template Builder. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 596 次。

如何安装 email-template-builder?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install email-template-builder」即可一键安装,无需额外配置。

email-template-builder 是免费的吗?

是的,email-template-builder 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

email-template-builder 支持哪些平台?

email-template-builder 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 email-template-builder?

由 Alireza Rezvani(@alirezarezvani)开发并维护,当前版本 v1.0.0。

💬 留言讨论