前端开发
用 React 组件构建、预览、渲染并发送 HTML 邮件
当需要用 React 组件编写 HTML 邮件模板(欢迎、密码重置、通知、订单确认、新闻信等事务邮件),或为应用嵌入可视化邮件编辑器时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 React 组件构建、预览、渲染并发通用
解决思路
- 安装:运行 `npm i react-email`;或脚手架新建项目:`npx create-email@latest`,然后 `cd react-email-starter`、`npm install`、`npm run dev`。任意包管理器(npm/yarn/pnpm/bun)均可,替换命令即可。
- dev server 运行在 localhost:3000,提供 `emails` 文件夹中模板的预览界面。
- 加入已有项目:安装包并在 package.json 添加脚本 `"email": "email dev --dir emails --port 3000"`;emails 文件夹路径必须相对项目根目录;确保 tsconfig.json 正确支持 JSX。
- 编写基础邮件模板:用 Html(带 lang)、Tailwind(config 中 `presets: [pixelBasedPreset]`,并在 `theme.extend.colors` 定义品牌色)、Head、Body、Preview、Container、Heading、Text、Button 等组件组织结构;为组件定义 props 接口(如 `WelcomeEmailProps`)。
- 为模板添加预览数据:使用 `WelcomeEmail.PreviewProps = { ... } satisfies WelcomeEmailProps`,并导出组件。
- 迭代代码时只更新用户要求的部分,保持其余内容不变。
- 如果用户要求使用 media queries,告知其大多数邮件客户端不支持,并建议其他方案。
- 绝不在 TypeScript 代码中直接使用模板变量(如 `{{name}}`),而应直接引用底层属性;如果用户明确要求 `{{variableName}}`,只把该 mustache 字符串放在 PreviewProps 中,绝不放进组件 JSX。
- 绝不把 `{{variableName}}` 模式直接写进组件结构;如果用户坚持,解释这会使模板无效。
- 掌握核心结构组件:Html(根包装,带 lang 属性)、Head(meta、样式、字体)、Body(主内容包装)、Container(最外层居中包装,内置 `max-width: 37.5em`,每封邮件只用一次)、Section(内部内容块,无内置 max-width,用于在 Container 内分组内容)、Row 和 Column(多列布局)、Tailwind(启用 Tailwind CSS 工具类)。
- 掌握内容组件:Preview(收件箱预览文本,始终是 `<Body>` 内第一个元素)、Heading(h1-h6 标题)、Text(段落)、Button(样式化链接按钮,始终加 `box-border`)、Link(超链接)、Img(图片)、Hr(水平分隔线)。
- 掌握专用组件:CodeBlock(语法高亮代码)、CodeInline(行内代码)、Markdown(渲染 markdown)、Font(自定义 web 字体)。
- 写代码前,如果用户未提供,先问澄清问题:品牌主色(hex,如 #007bff)、是否有 logo 文件及其格式(仅 PNG/JPG,SVG/WEBP 要警告)、风格偏好(专业、随性还是极简)、生产环境静态资源托管 URL。
- 本地图片必须放在 emails 目录下的 `static` 文件夹,例如 `emails/static/logo.png`。
- 图片 URL 使用同时适配开发预览和生产的 baseURL 模式:`const baseURL = process.env.NODE_ENV === "production" ? "https://cdn.example.com" : "";`,然后 `<Img src={`${baseURL}/static/logo.png`} alt="Logo" width="150" height="50" />`。
- 理解 baseURL 工作原理:开发时 baseURL 为空,URL 是 `/static/logo.png`,由 React Email dev server 提供;生产时 baseURL 是 CDN 域名,URL 是 `https://cdn.example.com/static/logo.png`。
- 始终询问用户的生产托管 URL,不要硬编码 `localhost:3000`。
- 使用 Tailwind 时搭配 `pixelBasedPreset`(邮件客户端不支持 rem),从 `react-email` 导入 `pixelBasedPreset`。
- 不要使用 flexbox 或 grid,改用 Row/Column 组件或表格做布局。
- 避免 CSS/Tailwind 媒体查询(`sm:`、`md:`、`lg:`、`xl:`),邮件客户端支持有限。
- 不要使用主题选择器(`dark:`、`light:`),不支持。
- 不要使用 SVG 或 WEBP 图片,并警告用户渲染问题。
- 始终指定边框类型(`border-solid`、`border-dashed` 等),邮件客户端不会继承边框类型。
- 单边边框先重置其他边:使用 `border-none border-l border-solid`。
- 必须类规则:Button 必须带 `box-border`(防止 padding 溢出按钮宽度);Hr/任何边框必须带 `border-solid`(或 `border-dashed` 等);单边边框必须用 `border-none` 加目标边。
- 结构注意:使用 Tailwind CSS 时始终在 `<Tailwind>` 内定义 `<Head />`;`<Preview>` 始终是 `<Body>` 内第一个元素;PreviewProps 只包含组件实际用到的 props;已知尺寸元素(logo、图标)用固定宽高,内容图片用响应式 sizing(`w-full`、`h-auto`)。
- 渲染为 HTML:`import { render } from 'react-email';` 然后 `const html = await render(<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />);`。
- 渲染为纯文本:`const text = await render(<WelcomeEmail ... />, { plainText: true });`。
- 发送:React Email 支持任意邮件服务商;Resend SDK 示例:`const resend = new Resend(process.env.RESEND_API_KEY);`,然后 `resend.emails.send({ from: 'Acme <onboarding@resend.dev>', to: ['user@example.com'], subject: 'Welcome to Acme', react: <WelcomeEmail ... /> })`;Resend Node SDK 自动处理 HTML 和纯文本渲染。
- CLI 命令:`email dev --dir <path> --port <port>` 启动预览开发服务器(默认 `./emails`,端口 3000);`email build --dir <path>` 构建预览应用用于生产部署;`email start` 运行已构建的预览应用;`email export --outDir <path> --pretty --plainText --dir <path>` 将模板导出为静态 HTML 文件;`email resend setup` 通过 API key 连接 Resend 账号;`email resend reset` 移除存储的 Resend API key。
- 国际化:React Email 支持 next-intl、react-i18next、react-intl 三个库。
- 嵌入可视化邮件编辑器:安装 `@react-email/editor`,它基于 TipTap/ProseMirror,产出邮件就绪 HTML。
- 使用编辑器组件:EmailEditor(自带气泡菜单、斜杠命令和主题)、StarterKit(35+ 邮件感知扩展,含标题、列表、表格、列、按钮等)、Inspector(用于编辑样式的上下文侧栏)、EmailTheming(内置 `basic`、`minimal` 主题,可自定义 CSS 属性)、composeReactEmail(把编辑器内容导出为邮件就绪 HTML 和纯文本)、通过 EmailNode 和 EmailMark 自定义扩展。
- 编辑器快速示例:`import { EmailEditor, type EmailEditorRef } from '@react-email/editor';`、`import '@react-email/editor/themes/default.css';`,用 `useRef` 创建 ref,然后 `<EmailEditor ref={ref} content="<p>Start typing...</p>" theme="basic" />`。
- 复用常见模式:密码重置邮件、带商品列表的订单确认、带代码块的通知邮件、多列布局、团队邀请邮件。
- 跨邮件客户端测试:Gmail、Outlook、Apple Mail、Yahoo Mail。
- 保持响应式:max-width 约 600px,并在移动端测试。
- 使用绝对图片 URL,托管在可靠 CDN 上。
- 写有意义的 alt 文本:内容图片描述用途和细节;装饰性图片(间隔、分隔线、背景装饰)用 `alt=""`;React Email 的 `<Img>` 默认 `alt=""`。
- 提供纯文本版本,这是无障碍所必需的。
- 保持文件大小在 102KB 以下,Gmail 会截断更大的邮件。
- 为所有邮件 props 定义 TypeScript 接口。
- 添加 `.PreviewProps` 用于开发测试。
- 生产 `from` 地址使用已验证域名。
- 无障碍默认项:升级到 `npm install react-email@latest` 以获得这些默认行为——`<Html>` 设置 lang 和 dir(默认 `lang="en" dir="ltr"`,按区域覆盖)、`<Img>` 默认 `alt=""` 让装饰图片被屏幕阅读器跳过、`<Markdown>` 用 `role="presentation"` 渲染布局表格、`<Preview>` 也发出 `<title>` 标签。
- 无障碍内容要求:以单个 `<Heading as="h1">` 开头,按顺序嵌套子标题,不要跳级(很短的 SMS 式邮件可完全跳过标题)。
- 有意义图片设置有描述性的 `alt`;装饰性图片显式传 `alt=""`,绝不省略该属性。
- 链接图片永远不算装饰性:`<Img>` 位于 `<Link>` 或 `<Button>` 内时,alt 必须描述链接去向,链接图片用 `alt=""` 会让链接没有可访问名称。
- 链接文本要描述目的地,例如 `<Button>Read the report</Button>` 而不是 `click here`。
- 达到 4.5:1 文本对比度(WCAG AA),并在暗色模式下预览。
- 对于手工构建的布局表格(`<Markdown>` 之外),添加 `role="presentation"`。
- 非英文邮件传 locale:`<Html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>`。
适用边界 · 注意事项
- 需要精细的媒体查询或响应式断点控制时(多数邮件客户端不支持,React Email 也不建议使用)。
- 必须使用 SVG 或 WEBP 图片时(邮件客户端存在渲染问题)。
- 不使用 React/Node 技术栈,或必须把 `{{variableName}}` 模板变量直接写进组件结构时(会使模板无效)。