react-email by resend/react-email
npx skills add https://github.com/resend/react-email --skill react-email使用 React 组件构建和发送 HTML 电子邮件——一种适用于所有主流电子邮件客户端的现代、基于组件的电子邮件开发方法。
你需要使用 create-email CLI 来搭建一个新的 React Email 项目。这将创建一个名为 react-email-starter 的文件夹,其中包含示例电子邮件模板。
使用 npm:
npx create-email@latest
使用 yarn:
yarn create email
使用 pnpm:
pnpm create email
使用 bun:
bun create email
你必须切换到新创建的项目文件夹:
cd react-email-starter
在运行开发服务器之前,你需要安装所有项目依赖项。
使用 npm:
npm install
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
使用 yarn:
yarn
使用 pnpm:
pnpm install
使用 bun:
bun install
你的任务是启动本地预览服务器,以查看和编辑电子邮件模板。
使用 npm:
npm run dev
使用 yarn:
yarn dev
使用 pnpm:
pnpm dev
使用 bun:
bun dev
通过检查 localhost:3000 是否可以访问来确认开发服务器正在运行。服务器将显示一个预览界面,你可以在其中查看 emails 文件夹中的电子邮件模板。
假设 React Email 已安装在现有项目中,请更新顶层的 package.json 文件,添加一个脚本来运行 React Email 预览服务器。
{
"scripts": {
"email": "email dev --dir emails --port 3000"
}
}
确保电子邮件文件夹的路径相对于基础项目目录。
确保 tsconfig.json 包含对 jsx 的适当支持。
替换示例电子邮件模板。以下是创建新电子邮件模板的方法:
使用 Tailwind 组件进行样式设计,创建具有适当结构的电子邮件组件:
import {
Html,
Head,
Preview,
Body,
Container,
Heading,
Text,
Button,
Tailwind,
pixelBasedPreset
} from '@react-email/components';
interface WelcomeEmailProps {
name: string;
verificationUrl: string;
}
export default function WelcomeEmail({ name, verificationUrl }: WelcomeEmailProps) {
return (
<Html lang="en">
<Tailwind
config={{
presets: [pixelBasedPreset],
theme: {
extend: {
colors: {
brand: '#007bff',
},
},
},
}}
>
<Head />
<Preview>Welcome - Verify your email</Preview>
<Body className="bg-gray-100 font-sans">
<Container className="max-w-xl mx-auto p-5">
<Heading className="text-2xl text-gray-800">
Welcome!
</Heading>
<Text className="text-base text-gray-800">
Hi {name}, thanks for signing up!
</Text>
<Button
href={verificationUrl}
className="bg-brand text-white px-5 py-3 rounded block text-center no-underline box-border"
>
Verify Email
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
// Preview props for testing
WelcomeEmail.PreviewProps = {
name: 'John Doe',
verificationUrl: 'https://example.com/verify/abc123'
} satisfies WelcomeEmailProps;
export { WelcomeEmail };
完整的组件文档请参阅 references/COMPONENTS.md。
核心结构:
Html - 带有 lang 属性的根包装器Head - 元元素、样式、字体Body - 主要内容包装器Container - 居中内容(最大宽度布局)Section - 布局区块Row 和 Column - 多列布局Tailwind - 启用 Tailwind CSS 工具类内容:
Preview - 收件箱预览文本,始终位于 Body 内的第一个Heading - h1-h6 标题Text - 段落Button - 带样式的链接按钮Link - 超链接Img - 图像(请参阅下面的静态文件部分)Hr - 水平分隔线专用组件:
CodeBlock - 语法高亮的代码块CodeInline - 行内代码Markdown - 渲染 MarkdownFont - 自定义网页字体当用户请求电子邮件模板时,如果他们未提供以下信息,请先询问澄清问题:
对模糊请求的示例回复:
在我创建您的电子邮件模板之前,我有几个问题:
- 您的主要品牌颜色是什么?(十六进制代码)
- 您有 Logo 文件吗?(PNG 或 JPG - 注意:SVG 和 WEBP 在电子邮件客户端中无法可靠工作)
- 您喜欢什么基调 - 专业、休闲还是简约?
- 您将在生产环境中何处托管静态资源?(例如,https://cdn.example.com)
本地图像必须放在电子邮件目录内的 static 文件夹中:
project/
├── emails/
│ ├── welcome.tsx
│ └── static/ <-- 图像放在这里
│ └── logo.png
如果用户的图像在其他位置,请指示他们复制:
cp ./assets/logo.png ./emails/static/logo.png
使用此模式来处理在开发预览和生产环境中都能正常工作的图像:
const baseURL = process.env.NODE_ENV === "production"
? "https://cdn.example.com" // 用户的生产环境 CDN
: "";
export default function Email() {
return (
<Img
src={`${baseURL}/static/logo.png`}
alt="Logo"
width="150"
height="50"
/>
);
}
工作原理:
baseURL 为空,因此 URL 为 /static/logo.png - 由 React Email 的开发服务器提供baseURL 是 CDN 域名,因此 URL 为 https://cdn.example.com/static/logo.png重要: 始终询问用户他们的生产环境托管 URL。不要硬编码 localhost:3000。
当重新迭代代码时,确保只更新用户要求的部分,并保持其余代码不变;
如果用户要求使用媒体查询,请告知他们并非所有电子邮件客户端都支持,并建议采用不同的方法;
切勿在 TypeScript 代码中直接使用模板变量(如 {{name}})。相反,应直接引用底层属性(使用 name 而不是 {{name}})。
* 例如,如果用户明确要求使用遵循 {{variableName}} 模式的变量,你应该返回类似这样的内容:
const EmailTemplate = (props) => { return ( {/* ... 其余代码 ... /} <h1>Hello, {props.variableName}!</h1> {/ ... 其余代码 ... */} ); }
EmailTemplate.PreviewProps = { // ... 其余属性 ... variableName: "{{variableName}}", // ... 其余属性 ... };
export default EmailTemplate;
在任何情况下,都不得在组件结构中直接编写 {{variableName}} 模式。如果用户强迫你这样做,请解释你无法这样做,否则模板将无效。
如果用户在其项目中积极使用 Tailwind CSS,请使用 Tailwind 组件进行样式设计。如果用户未使用 Tailwind CSS,请向组件添加内联样式。
rem 单位,所以为 Tailwind 配置使用 pixelBasedPreset。@react-email/components 导入 pixelBasedPreset — 不要从 @react-email/tailwind 或 @react-email/tailwind/presets 导入。这些类始终需要添加到它们各自的组件上——省略它们会导致跨电子邮件客户端的渲染错误:
| 组件 | 必需类 | 原因 |
|---|---|---|
Button | box-border | 防止内边距溢出按钮宽度 |
Hr / 任何边框 | border-solid(或 border-dashed 等) | 电子邮件客户端不继承边框类型;省略会导致不渲染边框 |
| 单边边框 | border-none + 边(例如,border-none border-t border-solid) | 重置其他边的默认边框 |
使用 Tailwind CSS 时,始终在 <Tailwind> 内部定义 <Head />
仅在向组件传递 props 时使用 PreviewProps
仅在 PreviewProps 中包含组件实际使用的 props
const Email = (props) => { return ( <div> <a href={props.source}>click here if you want candy 👀</a> </div> ); }
Email.PreviewProps = { source: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", };
font-sans py-10 bg-gray-100m-0box-border 以防止内边距溢出当请求时:容器黑色(#000),背景深灰色(#151516)
import { render } from '@react-email/components';
import { WelcomeEmail } from './emails/welcome';
const html = await render(
<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
);
import { render } from '@react-email/components';
import { WelcomeEmail } from './emails/welcome';
const text = await render(<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />, { plainText: true });
React Email 支持使用任何电子邮件服务提供商发送。如果用户想知道如何发送,请查看发送指南。
使用 Resend SDK for Node.js 的快速示例:
import { Resend } from 'resend';
import { WelcomeEmail } from './emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'Acme <onboarding@resend.dev>',
to: ['user@example.com'],
subject: 'Welcome to Acme',
react: <WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
});
if (error) {
console.error('Failed to send:', error);
}
Node SDK 会自动为你处理纯文本渲染和 HTML 渲染。
完整的 i18n 文档请参阅 references/I18N.md。
React Email 支持三个 i18n 库:next-intl、react-i18next 和 react-intl。
import { createTranslator } from 'next-intl';
import {
Html,
Body,
Container,
Text,
Button,
Tailwind,
pixelBasedPreset
} from '@react-email/components';
interface EmailProps {
name: string;
locale: string;
}
export default async function WelcomeEmail({ name, locale }: EmailProps) {
const t = createTranslator({
messages: await import(\`../messages/\${locale}.json\`),
namespace: 'welcome-email',
locale
});
return (
<Html lang={locale}>
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Body className="bg-gray-100 font-sans">
<Container className="max-w-xl mx-auto p-5">
<Text className="text-base text-gray-800">{t('greeting')} {name},</Text>
<Text className="text-base text-gray-800">{t('body')}</Text>
<Button href="https://example.com" className="bg-blue-600 text-white px-5 py-3 rounded">
{t('cta')}
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
消息文件(messages/en.json、messages/es.json 等):
{
"welcome-email": {
"greeting": "Hi",
"body": "Thanks for signing up!",
"cta": "Get Started"
}
}
跨电子邮件客户端测试 - 在 Gmail、Outlook、Apple Mail、Yahoo Mail 中测试。使用 Litmus 或 Email on Acid 等服务进行绝对精确的测试,并使用 React Email 的工具栏检查特定功能支持。
保持响应式 - 最大宽度约为 600px,在移动设备上测试。
使用绝对图像 URL - 在可靠的 CDN 上托管,始终包含 alt 文本。
提供纯文本版本 - 这是可访问性和某些电子邮件客户端所必需的。
保持文件大小在 102KB 以下 - Gmail 会截断较大的电子邮件。
添加适当的 TypeScript 类型 - 为所有电子邮件 props 定义接口。
包含预览 props - 为组件添加 .PreviewProps 以进行开发测试。
处理错误 - 发送电子邮件时始终检查错误。
使用已验证的域名 - 对于生产环境,在 from 地址中使用已验证的域名。
完整的示例请参阅 references/PATTERNS.md,包括:
每周安装量
3.5K
仓库
GitHub Stars
18.3K
首次出现
Jan 21, 2026
安全审计
已安装于
opencode2.6K
codex2.5K
gemini-cli2.5K
github-copilot2.5K
claude-code2.5K
cursor2.4K
Build and send HTML emails using React components - a modern, component-based approach to email development that works across all major email clients.
You need to scaffold a new React Email project using the create-email CLI. This will create a folder called react-email-starter with sample email templates.
Using npm:
npx create-email@latest
Using yarn:
yarn create email
Using pnpm:
pnpm create email
Using bun:
bun create email
You must change into the newly created project folder:
cd react-email-starter
You need to install all project dependencies before running the development server.
Using npm:
npm install
Using yarn:
yarn
Using pnpm:
pnpm install
Using bun:
bun install
Your task is to start the local preview server to view and edit email templates.
Using npm:
npm run dev
Using yarn:
yarn dev
Using pnpm:
pnpm dev
Using bun:
bun dev
Confirm the development server is running by checking that localhost:3000 is accessible. The server will display a preview interface where you can view email templates from the emails folder.
Assuming React Email is installed in an existing project, update the top-level package.json file with a script to run the React Email preview server.
{
"scripts": {
"email": "email dev --dir emails --port 3000"
}
}
Make sure the path to the emails folder is relative to the base project directory.
Ensure the tsconfig.json includes proper support for jsx.
Replace the sample email templates. Here is how to create a new email template:
Create an email component with proper structure using the Tailwind component for styling:
import {
Html,
Head,
Preview,
Body,
Container,
Heading,
Text,
Button,
Tailwind,
pixelBasedPreset
} from '@react-email/components';
interface WelcomeEmailProps {
name: string;
verificationUrl: string;
}
export default function WelcomeEmail({ name, verificationUrl }: WelcomeEmailProps) {
return (
<Html lang="en">
<Tailwind
config={{
presets: [pixelBasedPreset],
theme: {
extend: {
colors: {
brand: '#007bff',
},
},
},
}}
>
<Head />
<Preview>Welcome - Verify your email</Preview>
<Body className="bg-gray-100 font-sans">
<Container className="max-w-xl mx-auto p-5">
<Heading className="text-2xl text-gray-800">
Welcome!
</Heading>
<Text className="text-base text-gray-800">
Hi {name}, thanks for signing up!
</Text>
<Button
href={verificationUrl}
className="bg-brand text-white px-5 py-3 rounded block text-center no-underline box-border"
>
Verify Email
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
// Preview props for testing
WelcomeEmail.PreviewProps = {
name: 'John Doe',
verificationUrl: 'https://example.com/verify/abc123'
} satisfies WelcomeEmailProps;
export { WelcomeEmail };
See references/COMPONENTS.md for complete component documentation.
Core Structure:
Html - Root wrapper with lang attributeHead - Meta elements, styles, fontsBody - Main content wrapperContainer - Centers content (max-width layout)Section - Layout sectionsRow & Column - Multi-column layoutsTailwind - Enables Tailwind CSS utility classesContent:
Preview - Inbox preview text, always first in BodyHeading - h1-h6 headingsText - ParagraphsButton - Styled link buttonsLink - HyperlinksImg - Images (see Static Files section below)Hr - Horizontal dividersSpecialized:
CodeBlock - Syntax-highlighted codeCodeInline - Inline codeMarkdown - Render markdownFont - Custom web fontsWhen a user requests an email template, ask clarifying questions FIRST if they haven't provided:
Example response to vague request:
Before I create your email template, I have a few questions:
- What is your primary brand color? (hex code)
- Do you have a logo file? (PNG or JPG - note: SVG and WEBP don't work reliably in email clients)
- What tone do you prefer - professional, casual, or minimal?
- Where will you host static assets in production? (e.g., https://cdn.example.com)
Local images must be placed in the static folder inside your emails directory:
project/
├── emails/
│ ├── welcome.tsx
│ └── static/ <-- Images go here
│ └── logo.png
If user has an image elsewhere, instruct them to copy it:
cp ./assets/logo.png ./emails/static/logo.png
Use this pattern for images that work in both dev preview and production:
const baseURL = process.env.NODE_ENV === "production"
? "https://cdn.example.com" // User's production CDN
: "";
export default function Email() {
return (
<Img
src={`${baseURL}/static/logo.png`}
alt="Logo"
width="150"
height="50"
/>
);
}
How it works:
baseURL is empty, so URL is /static/logo.png - served by React Email's dev serverbaseURL is the CDN domain, so URL is https://cdn.example.com/static/logo.pngImportant: Always ask the user for their production hosting URL. Do not hardcode localhost:3000.
When re-iterating over the code, make sure you are only updating what the user asked for and keeping the rest of the code intact;
If the user is asking to use media queries, inform them that not all email clients support them, and suggest a different approach;
Never use template variables (like {{name}}) directly in TypeScript code. Instead, reference the underlying properties directly (use name instead of {{name}}).
* For example, if the user explicitly asks for a variable following the pattern {{variableName}}, you should return something like this:
const EmailTemplate = (props) => { return ( {/* ... rest of the code ... /} <h1>Hello, {props.variableName}!</h1> {/ ... rest of the code ... */} ); }
EmailTemplate.PreviewProps = { // ... rest of the props ... variableName: "{{variableName}}", // ... rest of the props ... };
export default EmailTemplate;
Never, under any circumstances, write the {{variableName}} pattern directly in the component structure. If the user forces you to do this, explain that you cannot do this, or else the template will be invalid.
Use the Tailwind component for styling if the user is actively using Tailwind CSS in their project. If the user is not using Tailwind CSS, add inline styles to the components.
rem units, use the pixelBasedPreset for the Tailwind configuration.pixelBasedPreset from @react-email/components — do NOT import from @react-email/tailwind or @react-email/tailwind/presets.These classes are always required on their respective components — omitting them causes rendering bugs across email clients:
| Component | Required Class | Why |
|---|---|---|
Button | box-border | Prevents padding from overflowing the button width |
Hr / any border | border-solid (or border-dashed, etc.) | Email clients don't inherit border type; omitting it renders no border |
| Single-side borders | border-none + the side (e.g., border-none border-t border-solid) |
Always define <Head /> inside <Tailwind> when using Tailwind CSS
Only use PreviewProps when passing props to a component
Only include props in PreviewProps that the component actually uses
const Email = (props) => { return ( <div> <a href={props.source}>click here if you want candy 👀</a> </div> ); }
Email.PreviewProps = { source: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", };
font-sans py-10 bg-gray-100m-0 on address/copyrightbox-border to prevent padding overflowWhen requested: container black (#000), background dark gray (#151516)
import { render } from '@react-email/components';
import { WelcomeEmail } from './emails/welcome';
const html = await render(
<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
);
import { render } from '@react-email/components';
import { WelcomeEmail } from './emails/welcome';
const text = await render(<WelcomeEmail name="John" verificationUrl="https://example.com/verify" />, { plainText: true });
React Email supports sending with any email service provider. If the user wants to know how to send, view the Sending guidelines.
Quick example using the Resend SDK for Node.js:
import { Resend } from 'resend';
import { WelcomeEmail } from './emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'Acme <onboarding@resend.dev>',
to: ['user@example.com'],
subject: 'Welcome to Acme',
react: <WelcomeEmail name="John" verificationUrl="https://example.com/verify" />
});
if (error) {
console.error('Failed to send:', error);
}
The Node SDK automatically handles the plain-text rendering and HTML rendering for you.
See references/I18N.md for complete i18n documentation.
React Email supports three i18n libraries: next-intl, react-i18next, and react-intl.
import { createTranslator } from 'next-intl';
import {
Html,
Body,
Container,
Text,
Button,
Tailwind,
pixelBasedPreset
} from '@react-email/components';
interface EmailProps {
name: string;
locale: string;
}
export default async function WelcomeEmail({ name, locale }: EmailProps) {
const t = createTranslator({
messages: await import(\`../messages/\${locale}.json\`),
namespace: 'welcome-email',
locale
});
return (
<Html lang={locale}>
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Body className="bg-gray-100 font-sans">
<Container className="max-w-xl mx-auto p-5">
<Text className="text-base text-gray-800">{t('greeting')} {name},</Text>
<Text className="text-base text-gray-800">{t('body')}</Text>
<Button href="https://example.com" className="bg-blue-600 text-white px-5 py-3 rounded">
{t('cta')}
</Button>
</Container>
</Body>
</Tailwind>
</Html>
);
}
Message files (messages/en.json, messages/es.json, etc.):
{
"welcome-email": {
"greeting": "Hi",
"body": "Thanks for signing up!",
"cta": "Get Started"
}
}
Test across email clients - Test in Gmail, Outlook, Apple Mail, Yahoo Mail. Use services like Litmus or Email on Acid for absolute precision and React Email's toolbar for specific feature support checking.
Keep it responsive - Max-width around 600px, test on mobile devices.
Use absolute image URLs - Host on reliable CDN, always include alt text.
Provide plain text version - Required for accessibility and some email clients.
Keep file size under 102KB - Gmail clips larger emails.
Add proper TypeScript types - Define interfaces for all email props.
Include preview props - Add .PreviewProps to components for development testing.
Handle errors - Always check for errors when sending emails.
Use verified domains - For production, use verified domains in from addresses.
See references/PATTERNS.md for complete examples including:
Weekly Installs
3.5K
Repository
GitHub Stars
18.3K
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode2.6K
codex2.5K
gemini-cli2.5K
github-copilot2.5K
claude-code2.5K
cursor2.4K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
| Resets default borders on other sides |