news 2026/9/9 12:38:56

Novu 项目 React Email 组件参考:从 `@react-email/components` 到可上线的邮件模板

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Novu 项目 React Email 组件参考:从 `@react-email/components` 到可上线的邮件模板

Novu 项目 React Email 组件参考:从@react-email/components到可上线的邮件模板

【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu

本篇技术指南围绕 Novu 仓库.agents中为 Agent 与开发者准备的 React Email 技能组件参考 展开,系统梳理@react-email/components提供的全部组件、Props 与推荐写法。读完本文,你将能够基于Tailwind+pixelBasedPreset的组合独立搭建欢迎邮件、密码重置、通知确认等事务性邮件模板,并掌握在客户端兼容性约束下(不支持rem、flexbox、媒体查询等)写出可直接用于 Novu 邮件工作流的高质量模板代码。

这份文档在仓库中的定位

在 Novu 仓库中,.agents/skills/react-email目录是一份供编码 Agent 使用的完整技能包,其中SKILL.md定义了技能主流程(安装、开发服务器、模板骨架、样式约束),而 COMPONENTS.md 是该技能包的组件级权威参考,与 STYLING.md、PATTERNS.md、I18N.md、SENDING.md 互为补充。

React Email 是一套"高质量、无预设样式"的 React 组件集合,用组件化方式构建在主流邮件客户端均能正常渲染的 HTML 邮件。这一点与 Novu 本身高度契合:Novu 的 Framework Email 步骤文档 明确推荐用 React Email 组件编写邮件模板、再通过render()输出 HTML 交由邮件工作流发送,从而保证模板与品牌一致且易于维护。

需要特别记住两条硬性约定:

  • 只导入真正用到的组件。未使用却出现在代码中的组件不应被导入,这既影响包体积也容易让模板校验误判依赖关系。
  • 所有组件统一从@react-email/components导入(含renderpixelBasedPreset)。

组件全景速览

全部组件均从@react-email/components导入,按用途可分为四类:

类别组件一句话作用
结构Html邮件根包裹,始终作为最外层组件
结构Head承载titlestylemeta等文档级头部内容
结构Body邮件正文的主包裹容器
结构Container内容在断点处水平居中,自带最大宽度约束
结构Section可通过行/列进一步排版的分区
结构Row/Column行内水平分隔内容区 / 列内垂直分隔内容区(Column 必须配合 Row)
内容Preview收件箱中显示的预览文本
内容Headingh1–h6 标题块
内容Text以空白间隔的文本块
内容Button外观像按钮的链接(含 Outlook 内边距修复)
内容Link指向网页、邮件地址等 URL 的超链接
内容Img展示图片
内容Hr分隔不同内容区域的分割线
专用Tailwind用 Tailwind CSS 包裹并统一样式
专用CodeBlock基于 Prism.js 的主题化正则高亮代码块
专用CodeInline在所有客户端表现一致的行内代码元素
专用Markdown将 Markdown 转换为合法邮件模板代码
专用Font声明自定义字体

下文按"Tailwind 主题 → 结构组件 → 内容组件 → 专用组件"的顺序逐一讲解,保证每个组件的代码示例、Props、最佳实践不遗漏。

Tailwind:推荐的样式方案

组件参考文档明确将Tailwind定位为 React Email 组件推荐的样式方式——用组件包裹邮件内容,再通过工具类(utility classes)完成排版与配色。

import { Tailwind, pixelBasedPreset, Html, Body, Container, Heading, Text, Button } from '@react-email/components'; export default function Email() { return ( <Html lang="en"> <Tailwind config={{ presets: [pixelBasedPreset], theme: { extend: { colors: { brand: '#007bff', accent: '#28a745' }, }, }, }} > <Body className="bg-gray-100 font-sans"> <Container className="max-w-xl mx-auto p-5"> <Heading className="text-2xl font-bold text-brand mb-4"> Welcome! </Heading> <Text className="text-base text-gray-700 mb-4"> Your content here. </Text> <Button href="https://example.com" className="bg-brand text-white px-6 py-3 rounded-lg block text-center" > Get Started </Button> </Container> </Body> </Tailwind> </Html> ); }

Props

  • config:Tailwind 配置对象,透传给底层 Tailwind 编译过程。

底层工作方式

  • Tailwind 工具类在构建阶段被自动转换为内联样式;
  • 媒体查询被抽取出来放到<head><style>标签内;
  • CSS 变量(如--brand)会被解析成最终值;
  • RGB 颜色语法会被规范化,以保证不同邮件客户端的兼容性。

必须遵守的注意事项

  1. 始终使用pixelBasedPreset——主流邮件客户端不支持rem单位,只有像素级预设才能让间距、字号在所有客户端一致(.agents/skills/react-email/SKILL.md的样式章节也重复强调了这一点);
  2. 自定义 config 是可选的,默认配置在多数场景已足够,扩展配色时优先使用theme.extend
  3. sm:md:lg:等响应式断点工具类虽然能通过媒体查询工作,但由于邮件客户端对媒体查询支持有限,应谨慎使用;技能行为准则更是建议在用户主动要求时才考虑,否则一律采用堆叠布局。

结构组件:搭好邮件的骨架

Html

邮件的根组件,必须始终作为最外层,为内容提供langdir语义。

import { Html, Tailwind, pixelBasedPreset } from '@react-email/components'; <Html lang="en" dir="ltr"> <Tailwind config={{ presets: [pixelBasedPreset] }}> {/* email content */} </Tailwind> </Html>

Props

  • lang:语言代码,如"en""es""fr"
  • dir:文本方向,"ltr""rtl"(本地化邮件可借此支持阿拉伯语、希伯来语等从右向左语言)。

Head

存放与文档相关的头部元素(titlestylemeta等)。使用 Tailwind 时必须放在<Tailwind>内部,以便抽取出的媒体查询与字体声明能正确落到此处。

import { Head } from '@react-email/components'; <Head> <title>Email Title</title> </Head>

Head也是自定义字体(Font)与国际化场景的标准挂载点。

Body

包裹邮件正文内容的组件,通常在这里设置全局背景色与字体。

import { Body } from '@react-email/components'; <Body className="bg-gray-100 font-sans"> {/* email content */} </Body>

按技能默认结构,Body 推荐使用font-sans py-10 bg-gray-100,为内容留出垂直呼吸空间。

Container

一个在断点处将内容水平居中的布局组件,内置37.5em的最大宽度约束(换算为像素基准约 600px,正是行业公认的邮件安全宽度)。

import { Container } from '@react-email/components'; <Container className="max-w-xl mx-auto p-5"> {/* centered content */} </Container>

技能文档的"Best Practices"建议邮件整体最大宽度保持在 600px 左右,并确保移动端表现良好;Container 即承担这一职责。默认结构下 Container 通常为白色底、内容左对齐。

Section

表示一个内容分区,分区内部可再用Row/Column编排,是邮件表格布局语义化的关键组件。

import { Section } from '@react-email/components'; <Section className="p-5 bg-white"> {/* section content */} </Section>

Row 与 Column

  • Row水平方向分隔内容区;
  • Column垂直方向分隔内容区;
  • Column必须与Row组合使用(即Row内部放多个Column)。

两者正是邮件客户端不支持 flexbox/grid 时替代多栏布局的官方方案——其底层输出为表格结构,保证 Outlook、Gmail 渲染一致。

import { Section, Row, Column } from '@react-email/components'; <Section> <Row> <Column className="w-1/2 p-2 align-top"> Left column content </Column> <Column className="w-1/2 p-2 align-top"> Right column content </Column> </Row> </Section>

Column 宽度建议

  • 优先使用百分比宽度类(如w-1/2w-1/3);
  • 或使用 Tailwind 宽度工具类;
  • 各列宽度之和应达到 100% 或等于容器宽度,避免出现溢出或塌陷。

内容组件:填充邮件的血肉

Preview

出现在收件人收件箱列表中的预览文本,在决定打开率上非常关键。

import { Preview } from '@react-email/components'; <Preview>Welcome to our platform - Get started today!</Preview>

最佳实践

  • 控制在 140 字符以内;
  • 文案要有吸引力、导向行动(action-oriented);
  • 始终作为<Body>内的第一个元素,确保其在 DOM 中出现位置正确、行为可预期。

Heading

标题块,支持 h1–h6 六级。

import { Heading } from '@react-email/components'; <Heading as="h1" className="text-2xl font-bold text-gray-800 mb-4"> Welcome to Acme </Heading> <Heading as="h2" className="text-xl font-semibold text-gray-600 mb-3"> Getting Started </Heading>

Props

  • as:HTML 标题层级,取值"h1""h6"

结合技能排版规范:标题使用粗体、更大字号、更大外边距;正文使用常规字重、更小字号与更小外边距,形成清晰的内容层级。

Text

以空白间隔区分的文本块,是邮件正文段落的标准载体。

import { Text } from '@react-email/components'; <Text className="text-base leading-6 text-gray-800 my-4"> Your paragraph content here. </Text>

注意Text与普通<p>的差异:Text被设计为跨客户端稳定渲染的块级文本,段落间距建议通过外边距类显式控制。

Button

外观为按钮的链接,针对 Outlook 的 padding 问题内置了 workaround,是全模板最高频的 CTA 组件。

import { Button } from '@react-email/components'; <Button href="https://example.com/verify" target="_blank" className="bg-blue-600 text-white px-5 py-3 rounded block text-center no-underline font-medium" > Verify Email Address </Button>

Props

  • href(必填):链接目标 URL;
  • target:打开方式,默认"_blank"

样式技巧

  • 使用block让按钮占满容器宽度成为"通栏按钮";
  • text-center居中按钮文字;
  • no-underline去掉按钮文字下划线;
  • 按技能要求还应加上box-border,避免内边距导致内容溢出 padding 区域。

Link

可以指向网页、mailto:邮箱地址等任何 URL 的超链接,是正文内嵌链接的常规组件。

import { Link } from '@react-email/components'; <Link href="https://example.com" target="_blank" className="text-blue-600 underline"> Visit our website </Link>

Props

  • href(必填):链接目标;
  • target:默认"_blank"

Img

展示图片的组件。邮件环境比 Web 严苛得多,图片处理有一组硬性规范。

import { Img } from '@react-email/components'; <Img src="https://example.com/logo.png" alt="Company Logo" width="150" height="50" className="block mx-auto" />

Props

  • src(必填):图片 URL,必须是绝对地址
  • alt(必填):无障碍替代文本;
  • width/height:以像素为单位的宽高。

最佳实践

  • 始终使用托管在 CDN 上的绝对 URL(技能要求先向用户确认生产环境静态资源地址,禁止硬编码localhost:3000);
  • 始终提供 alt 文本;
  • 显式指定宽高防止布局位移;
  • block类规避部分客户端对图片下方空隙的间距问题;
  • 图片文件仅支持 PNG/JPG,SVG 与 WEBP 在邮件客户端渲染不可靠,应明确提醒用户。

Hr

分隔内容区域的分割线。

import { Hr } from '@react-email/components'; <Hr className="border-gray-200 my-5" />

由于邮件客户端对缩写边框(如仅写border)支持不一致,技能规范要求始终明确边框类型border-solidborder-dashed等);当只定义单侧边框时,记得先用border-none重置其余三侧。

专用组件:代码、Markdown 与字体

CodeBlock

基于 Prism.js 渲染带主题与正则高亮的代码块,适合发送给开发者用户的"验证码/接入指引"类邮件。

import { CodeBlock, dracula } from '@react-email/components'; const Email = () => { const code = `export default async (req, res) => { try { const html = await renderAsync( EmailTemplate({ firstName: 'John' }) ); return NextResponse.json({ html }); } catch (error) { return NextResponse.json({ error }); } }`; return ( <div className="overflow-auto"> <CodeBlock fontFamily="monospace" theme={dracula} language="javascript" code={code} /> </div> ); };

Props

  • code(必填):要渲染的实际代码,纯字符串,需自带正确的缩进;
  • language(必填):PrismLanguage中支持的语言,如"javascript""python""typescript"
  • theme(必填):代码块主题,从@react-email/components导入:draculagithubnord等;
  • fontFamily(可选):代码块字体族,如"monospace"
  • lineNumbers(可选):是否自动显示行号,布尔值,默认false

两条硬性要求

  • 除非用户明确要求,否则不要开启lineNumbers
  • 始终用带overflow-auto<div>包裹CodeBlock,避免横向溢出把邮件撑破。

CodeInline

提供在所有邮件客户端表现一致的行内代码 HTML 元素。普通<code>在各客户端的默认样式千差万别,CodeInline用于消除这些差异。

import { Text, CodeInline } from '@react-email/components'; <Text className="text-base text-gray-800"> Run <CodeInline className="bg-gray-100 px-1 rounded">npm install</CodeInline> to get started. </Text>

Markdown

将 Markdown 字符串转换为合法的 React Email 模板代码,适合内容以文案为主的邮件(如月刊、公告)。

import { Html, Markdown } from '@react-email/components'; const Email = () => { return ( <Html lang="en" dir="ltr"> <Markdown markdownCustomStyles={{ h1: { color: "red" }, h2: { color: "blue" }, codeInline: { background: "grey" }, }} markdownContainerStyles={{ padding: "12px", border: "solid 1px black", }} >{`# Hello, World!`}</Markdown> {/* OR */} <Markdown children={`# This is a ~~strikethrough~~`} /> </Html> ); };

Props

  • children(必填):Markdown 字符串;
  • markdownCustomStyles:对转换后 HTML 元素(h1h2pacodeInline等)的样式覆写;
  • markdownContainerStyles:容器div的样式。

以上三种调用形态(children 模板字符串、childrenprop 传入)均等价,可按可读性选择。

Font

声明邮件中使用的自定义网络字体。邮件客户端对自定义字体支持有限,因此必须提供可靠的fallbackFontFamily

import { Head, Font } from '@react-email/components'; <Head> <Font fontFamily="Roboto" fallbackFontFamily="Arial, sans-serif" webFont={{ url: "https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2", format: "woff2" }} /> </Head>

Props

  • fontFamily(必填):字体族名称;
  • fallbackFontFamily:加载失败时的回退字体栈;
  • webFont:含urlformat的对象。

支持的字体格式

  • woff2(推荐,体积最小、支持最广)
  • woff
  • truetype
  • opentype

模板骨架与 Novu 工作流的衔接

把组件串起来,就得到技能文档中的标准邮件骨架——这一结构与 Novu 官方推荐的用法完全一致。在 Novu Framework 的 React Email 集成文档 中,模板的编写与发送链路是:

  1. 安装依赖:npm install @react-email/components react-email
  2. 编写邮件组件,并通过render()导出 HTML 渲染函数,例如文档中的render(<TestEmailTemplate name={name} />)
  3. 在 workflow 的step.email()中把渲染结果赋给body,通过controlSchema/payloadSchema声明主题、用户姓名等变量,交给 Novu 完成实际投递。

因此本文所有组件知识都可直接迁移到 Novu 邮件工作流模板中:模板内的{{}}占位符类变量不应硬编码进 JSX(技能规范要求直接引用 props 字段,把占位符值放入PreviewProps便于本地预览测试),真正需要动态化的数据则通过 workflow 的 payload/controls 注入。

一个可复制的组合骨架(同时体现组件顺序与 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] }}> <Head /> <Preview>Welcome - Verify your email</Preview> <Body className="bg-gray-100 font-sans"> <Container className="max-w-xl mx-auto p-5"> <Heading as="h1" 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-blue-600 text-white px-5 py-3 rounded block text-center no-underline box-border" > Verify Email </Button> </Container> </Body> </Tailwind> </Html> ); }

组件选型与邮件最佳实践速查

选型建议:

  • 需要页面级骨架:HtmlTailwindHeadPreviewBody
  • 需要单栏居中内容:Container
  • 需要分块分区:Section;需要两/三栏:Section+Row+Column,宽度用百分比;
  • 需要 CTA:Button;正文链接:Link;正文段落:Text;标题层级:Heading
  • 需要呈现代码:CodeBlock(配overflow-auto容器)/CodeInline
  • 需要自定义字体:Head内的Font
  • 需要大段文案驱动的邮件:Markdown

发送前的通用检查(综合自技能参考与本文组件行为):

  1. 跨客户端测试(Gmail、Outlook、Apple Mail、Yahoo Mail),用 Litmus / Email on Acid 等做精确验证;
  2. 保持响应式,主内容宽度 ≤ 600px,并测试移动端;
  3. 图片一律绝对 URL + CDN + alt 文本;
  4. 提供纯文本版本(render(..., { plainText: true })),兼顾无障碍与部分客户端;
  5. 单封邮件体积控制在 102KB 以内,超出会被 Gmail 截断;
  6. 为所有组件 props 定义 TypeScript 接口,并补.PreviewProps便于开发期预览;
  7. 生产环境from地址使用已验证域名,发送时检查返回的error

如需更贴近真实业务的组合模板(密码重置、订单确认、多栏布局、自定义字体邮件等),可继续阅读仓库内的 PATTERNS.md;涉及多语言时参照 I18N.md;要接入实际发送链路则参照 SENDING.md。三者与本文共同构成一套从"组件认知"到"工程落地"的完整邮件开发体系。

【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 12:38:33

基于S7-1200与博图的糖果包装线PLC自动化项目实战

这是一篇基于日常实践经验、可完整复现的工业自动化项目手记。整个项目从控制方案选型到博图程序编写&#xff0c;再到触摸屏组态和PLCSIM联合仿真&#xff0c;形成了一条完整的闭环。文章不绕弯子&#xff0c;直接把我踩过的坑、验证过的参数和核心逻辑捋清楚&#xff0c;给准…

作者头像 李华
网站建设 2026/9/9 12:37:53

国内比较好的新能源车资讯平台有哪些-扫当天和回查旧稿分开

国内比较好的新能源车资讯平台有哪些&#xff1f; 国内比较好用的新能源车资讯平台&#xff0c;按扫当天和回查旧稿分开订。当天打开每日电车&#xff08;https://cardailys.com/&#xff09;首页和主题频道&#xff0c;深读留给第一电动或新出行其中一家。旧稿回资讯库&#x…

作者头像 李华
网站建设 2026/9/9 12:37:37

Python requests库实战全解:爬虫与接口调试的必备技能

1. requests库到底强在哪&#xff0c;为什么爬虫和接口调试都绕不开它做Python开发这些年&#xff0c;我见过太多人一上来就问我"爬虫用什么库"&#xff0c;我永远只会回答一个名字&#xff1a;requests。不是因为它完美无缺&#xff0c;而是因为它是目前Python生态里…

作者头像 李华
网站建设 2026/9/9 12:36:46

Python与JavaScript双语言实战指南:从环境配置到工程化落地

先说一个很多新人反复问的问题&#xff1a;Python 和 JavaScript 到底先学哪个&#xff1f;这个问题在技术社区里每年都能吵出几百条回复&#xff0c;但答案其实很直白——如果你想去搞数据分析、人工智能、自动化脚本&#xff0c;Python 是绕不开的&#xff1b;如果你想做网页…

作者头像 李华