首页龙虾技能列表 › email-template-builder — 电子邮件模板构建器

email-template-builder — 电子邮件模板构建器

v1.0.0

电子邮件模板构建器,用于生成完整的交易性电子邮件系统,支持React Email模板、多提供商集成、预览服务器、国际化、暗模式、垃圾邮件优化和分析跟踪。输出适用于Resend、Postmark、SendGrid和AWS SES的生产就绪代码。

0· 393·0 当前·0 累计
by @alirezarezvani·MIT-0
下载技能包
License
MIT-0
最后更新
2026/3/11
安全扫描
VirusTotal
无害
查看报告
OpenClaw
安全
high confidence
该技能仅提供指令和电子邮件模板/代码生成指南,其要求和指令与声明的目的保持一致,不请求异常权限或凭据。
评估建议
该技能仅为模板和代码生成器。在使用前,请检查生成的代码中是否有硬编码的URL或跟踪像素,避免在示例文件中粘贴生产API密钥。通过自己的项目环境变量或秘密存储提供提供商凭据(Resend/Postmark/SendGrid/AWS SES),并确保退订/分析处理符合您的隐私和可送达性要求。如果技能请求云或电子邮件提供商凭据、或指示代理读取本地文件或上传数据到外部服务器,请停止并重新评估。...
详细分析 ▾
用途与能力
名称/描述(电子邮件模板构建器)与SKILL.md内容匹配:模板、布局、提供商适配器示例、预览服务器、国际化、暗模式和跟踪。元数据或SKILL.md中没有请求无关的系统访问或凭据。
指令范围
SKILL.md提供项目脚手架和代码示例(React Email、MJML、预览服务器、提供商适配器存根)。它引用外部资产(网页字体URL、徽标URL)和占位符(如{{unsubscribe_url}}),并描述添加打开/点击跟踪和UTM参数。指令不指示代理读取用户文件、环境变量或传输机密,但生成的代码将在部署时需要用户提供的提供商凭据——文档不自动配置这些。
安装机制
没有安装规范和代码文件;这是指令式的。没有下载或由技能本身执行的内容。
凭证需求
该技能没有声明所需的环境变量或凭据。这对于代码/模板生成器是合理的。(注意:真实的发送集成将需要提供商API密钥,用户必须在实现/部署生成的代码时提供。)
持久化与权限
该技能不是始终启用的,并且不请求持久或跨技能配置。它不尝试修改其他技能或系统设置。
安全有层次,运行前请审查代码。

License

MIT-0

可自由使用、修改和再分发,无需署名。

运行时依赖

无特殊依赖

版本

latestv1.0.02026/3/11
● 无害

安装命令 点击复制

官方npx clawhub@latest install email-template-builder
镜像加速npx clawhub@latest install email-template-builder --registry https://cn.clawhub-mirror.com

技能文档

等级: 强大 类别: 工程团队 领域: 事务性邮件 / 通信基础设施

概述

构建完整的事务性邮件系统:React Email 模板、邮件服务商集成、预览服务器、i18n 支持、深色模式、垃圾邮件优化和分析追踪。输出可用于 Resend、Postmark、SendGrid 或 AWS SES 的生产级代码。

核心功能

  • React Email 模板(欢迎邮件、验证邮件、密码重置、发票、通知、周报)
  • MJML 模板以实现最大的邮件客户端兼容性
  • 统一发送接口支持多服务商
  • 带热重载的本地预览服务器
  • 带类型化翻译键的 i18n/本地化
  • 使用媒体查询的深色模式支持
  • 垃圾邮件分数优化检查清单
  • 带 UTM 参数的打开/点击追踪

使用场景

  • 为新产品设置事务性邮件
  • 从传统邮件系统迁移
  • 添加新的邮件类型(发票、周报、通知)
  • 调试邮件投递问题
  • 为邮件模板实现 i18n

项目结构

emails/
├── components/
│   ├── layout/
│   │   ├── email-layout.tsx # 基础布局,包含品牌页眉/页脚
│   │   └── email-button.tsx # CTA 按钮组件
│   ├── partials/
│   │   ├── header.tsx
│   │   └── footer.tsx
├── templates/
│   ├── welcome.tsx
│   ├── verify-email.tsx
│   ├── password-reset.tsx
│   ├── invoice.tsx
│   ├── notification.tsx
│   └── weekly-digest.tsx
├── lib/
│   ├── send.ts # 统一发送函数
│   ├── providers/
│   │   ├── resend.ts
│   │   ├── postmark.ts
│   │   └── ses.ts
│   └── tracking.ts # UTM + 分析
├── i18n/
│   ├── en.ts
│   └── de.ts
└── preview/ # 开发预览服务器
    └── server.ts

基础邮件布局

// 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 ( {/ Dark mode styles /} {preview} {/ Header /}

MyApp
{/ Content /}
{children}
{/ Footer /}
MyApp Inc. · 123 Main St · San Francisco, CA 94105 Unsubscribe {" · "} Privacy Policy
) }

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", }, }

欢迎邮件

// 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 ( Welcome to MyApp, ${name}! Confirm your email to get started.}> Welcome to MyApp, {name}! We're excited to have you on board. You've got {trialDays} days to explore everything MyApp has to offer — no credit card required. First, confirm your email address to activate your account: Button not working? Copy and paste this link into your browser:
{confirmUrl}
Once confirmed, you can:

    • Connect your first project in 2 minutes
    • Invite your team (free for up to 3 members)
    • Set up Slack notifications
) }

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", }, }

发票邮件

// 发票邮件模板
// 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 ( 发票 ${invoiceNumber} - ${formatter.format(total / 100)}}> 发票 #{invoiceNumber} Hi {name}, 这是您来自 MyApp 的发票。感谢您一直以来的支持。

{/ 发票元数据 /}

发票日期 {invoiceDate} 到期日期 {dueDate} 应付金额 {formatter.format(total / 100)}

{/ 明细项目 /}

描述 金额 {items.map((item, i) => ( {item.description} {formatter.format(item.amount / 100)} ))}
合计 {formatter.format(total / 100)}

) }

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", }, }


统一发送函数

// 邮件发送库
// 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[0] } | { type: "invoice"; props: Parameters[0] }

export async function sendEmail(to: string, payload: EmailPayload) { const templates = { welcome: { component: WelcomeEmail, subject: "欢迎来到 MyApp — 请确认您的邮箱", }, invoice: { component: InvoiceEmail, subject: 来自 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 ", to, subject: template.subject, html: trackedHtml, tags: [{ name: "email-type", value: payload.type }], })

return result }


预览服务器设置

// package.json 脚本
{
  "scripts": {
    "email:dev": "email dev --dir emails/templates --port 3001",
    "email:build": "email export --dir emails/templates --outDir emails/out"
  }
}

// 运行:npm run email:dev // 打开:http://localhost:3001 // 显示所有模板的实时预览和热重载


国际化支持

// 英文翻译
// 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: "确认邮箱地址",
  },
}

// 德文翻译 // 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", }, }

// 在模板中使用 import { en, de } from "../i18n"

const t = locale === "de" ? de : en


垃圾邮件分数优化检查清单

  • [ ] 发件人域名已配置 SPF、DKIM 和 DMARC 记录
  • [ ] 发件人地址使用您自己的域名(不是 gmail.com/hotmail.com)
  • [ ] 主题行少于 50 个字符,不使用全大写,不使用 "FREE!!!"
  • [ ] 文本与图片比例:至少 60% 为文本
  • [ ] HTML 版本附带纯文本版本
  • [ ] 每封营销邮件包含退订链接(CAN-SPAM、GDPR)
  • [ ] 不使用 URL 缩短器 — 使用完整的品牌链接
  • [ ] 主题行中避免敏感词:"guarantee"、"no risk"、"limited time offer"
  • [ ] 每封邮件一个 CTA — 不使用 5 个不同的按钮
  • [ ] 每张图片都有 alt 文本
  • [ ] HTML 验证通过 — 无破损标签
  • [ ] 首次发送前使用 Mail-Tester.com 测试(目标:9+/10)

分析跟踪

// 邮件跟踪库
// 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()

// 为邮件中的所有链接添加 UTM 参数 return html.replace(/href="(https?:\/\/[^"]+)"/g, (match, url) => { const separator = url.includes("?") ? "&" : "?" return href="${url}${separator}${utmString}" }) }


常见陷阱

  • 必须使用内联样式 — 大多数邮件客户端会剥离 样式;React Email 会处理这个问题
  • 最大宽度 600px — 超过这个宽度在 Gmail 移动端会显示异常
  • 不支持 flexbox/grid — 使用 react-email 的 ,而不是 CSS grid
  • 深色模式媒体查询 — 必须使用 !important 来覆盖内联样式
  • 缺少纯文本版本 — 所有主流邮件提供商都有纯文本字段;务必填充它
  • 事务性邮件 vs 营销邮件 — 使用单独的发件域名/IP 来保护送达率
数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制

免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制

了解定制服务