ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Novu 仓库 Agent 技能实战:基于 React Email 与 Tailwind 的通用邮件模板模式详解

Novu 仓库 Agent 技能实战:基于 React Email 与 Tailwind 的通用邮件模板模式详解 Novu 仓库 Agent 技能实战基于 React Email 与 Tailwind 的通用邮件模板模式详解【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu本技能文档沉淀于本仓库.agents/skills/react-email/目录供研发 Agent 在编写 HTML 邮件模板时直接引用。它以「真实业务模板」为骨架给出密码重置、订单确认、通知告警、多栏 Newsletter、团队邀请五类高频场景的完整 React Email Tailwind CSS 实现并内置了pixelBasedPreset像素化预设、TypeScript 类型、PreviewProps预览数据与响应式布局等工程约定。读完本文你既能直接复制改造出可运行的邮件组件也能理解 React Email 在「一次编写、多邮件客户端兼容」前提下做复杂版式的核心写法。一、本文档的定位与所在仓库背景该技能文档位于仓库.agents/skills/react-email/references/PATTERNS.md是其父技能 .agents/skills/react-email/SKILL.md 的附属参考材料。SKILL.md 描述了技能启用范围当用户需要用 React 组件编写 HTML 邮件模板——欢迎邮件、密码重置、通知、订单确认、Newsletter 或事务邮件时调用本技能。配套参考还包括完整组件参考 references/COMPONENTS.md、样式指南 references/STYLING.md、发送指南 references/SENDING.md 与国际化指南 references/I18N.md。本文档本身不讲述组件 API而是直接给出 5 个端到端可运行的完整模板文件回答一个现实问题真实产品里最常见的邮件到底该怎么写。它同时承担着向 Agent 输出标准答案的角色因此每个示例都刻意做到全部样式走 Tailwind CSS 工具类且必须传入pixelBasedPreset预设为每个模板定义严格的 TypeScriptProps接口每个模板附带.PreviewProps静态属性用于本地预览与开发调试覆盖多栏布局、列表渲染、代码高亮、CTA 按钮、退订链接等复杂场景。二、五个示例背后的公共约定在逐个分析模板前先提炼它们在代码结构上的共性。理解这些约定后阅读甚至自行编写任何一封 React Email 邮件都会更顺畅。这些约定与 SKILL.md 中的Styling considerations和 references/STYLING.md 一脉相承根结构固定为Html langen→Tailwind config{{ presets: [pixelBasedPreset] }}→Head /→Body→Container。其中Head /在启用 Tailwind 时必须放在Tailwind内部。为何必须使用pixelBasedPreset绝大多数邮件客户端不支持rem单位。pixelBasedPreset会将 Tailwind 基于 rem 的工具类换算为像素值。这是 React Email Tailwind 写邮件的头号硬性约束五个示例无一例外全部传入该预设。布局禁用 flexbox/grid邮件客户端大多不解析 flex/grid复杂布局必须用SectionRowColumn组成的表格式结构Order Confirmation 与 Newsletter 示例是典型代表。预览文本Preview始终紧跟Head /之后、作为Body内第一个语义内容控制收件箱列表里显示的那一行摘要。通过静态属性.PreviewProps提供演示数据方便本地 dev server 直接渲染查看无需真实数据源。禁用媒体查询sm:/md:等、dark:主题选择器、SVG/WEBP 图片文案中的日期等动态值用 JS 内置 API 格式化。三、密码重置邮件单卡片 单一 CTA 的范式密码重置是事务邮件的入门标准件头部标题 说明文字 唯一行动按钮 安全提示脚注。React Email 组件版见下完整代码即文档原始实现import { Html, Head, Preview, Body, Container, Heading, Text, Button, Hr, Tailwind, pixelBasedPreset } from react-email/components; interface PasswordResetProps { resetUrl: string; email: string; expiryHours?: number; } export default function PasswordReset({ resetUrl, email, expiryHours 1 }: PasswordResetProps) { return ( Html langen Tailwind config{{ presets: [pixelBasedPreset] }} Head / PreviewReset your password - Action required/Preview Body classNamebg-gray-100 font-sans Container classNamemx-auto py-10 px-5 max-w-xl bg-white Heading classNametext-2xl font-bold text-gray-800 mb-5 Reset Your Password /Heading Text classNametext-base leading-7 text-gray-800 my-4 A password reset was requested for your account: strong{email}/strong /Text Text classNametext-base leading-7 text-gray-800 my-4 Click the button below to reset your password. This link expires in {expiryHours} hour{expiryHours 1 ? s : }. /Text Button href{resetUrl} classNamebg-red-600 text-white px-7 py-3.5 rounded block text-center font-bold my-6 no-underline Reset Password /Button Hr classNameborder-gray-200 my-6 / Text classNametext-sm text-gray-500 leading-5 my-2 If you didnt request this, please ignore this email. Your password will remain unchanged. /Text Text classNametext-sm text-gray-500 leading-5 my-2 For security, this link will only work once. /Text /Container /Body /Tailwind /Html ); } PasswordReset.PreviewProps { resetUrl: https://example.com/reset/abc123, email: userexample.com, expiryHours: 1 } as PasswordResetProps;该示例值得学习的写法Props 默认值下沉到组件签名expiryHours 1让调用方可以不传有效期复数处理用内联三元hour{expiryHours 1 ? s : }避免引入额外的复数库。按钮块级化Button的 className 使用block text-center让整行都可点击、文字居中同时no-underline去除超链接下划线。按 references/COMPONENTS.md 的说明Button本身已内置 Outlook 内边距问题的工作区。字号体系分三层主标题text-2xl font-bold→ 正文text-base leading-7→ 提示文字text-sm text-gray-500通过字号、字重、颜色三层差异建立视觉层级。.PreviewProps的as断言以} as PasswordResetProps结束保证静态属性里的示例数据与接口严格一致示例中resetUrl等均为演示占位 URL。安全话术是事务邮件刚需用Hr /把正文与免责提示分隔第二段提示该链接仅可使用一次属于密码重置场景的标配安全文案。四、订单确认邮件Row/Column 双栏版式与金额表格订单确认的核心难点是逐行商品列表与金额小计/运费/税费/合计的右对齐表格这要求在两列乃至三列版式下精确对齐。由于邮件客户端不支持 flexReact Email 用RowColumn以表格语义实现。文档原始实现如下import { Html, Head, Preview, Body, Container, Section, Row, Column, Heading, Text, Img, Hr, Tailwind, pixelBasedPreset } from react-email/components; interface Product { name: string; price: number; quantity: number; image: string; sku?: string; } interface OrderConfirmationProps { orderNumber: string; orderDate: Date; items: Product[]; subtotal: number; shipping: number; tax: number; total: number; shippingAddress: { name: string; street: string; city: string; state: string; zip: string; country: string; }; } export default function OrderConfirmation({ orderNumber, orderDate, items, subtotal, shipping, tax, total, shippingAddress }: OrderConfirmationProps) { return ( Html langen Tailwind config{{ presets: [pixelBasedPreset] }} Head / PreviewOrder #{orderNumber} confirmed - Thank you for your purchase!/Preview Body classNamebg-gray-100 font-sans Container classNamemx-auto py-10 px-5 max-w-xl Heading classNametext-3xl font-bold text-gray-800 mb-2 Order Confirmed /Heading Text classNametext-base text-gray-500 mb-6Thank you for your order!/Text Section classNamebg-gray-50 p-4 rounded mb-6 Row Column Text classNametext-xs text-gray-500 uppercase mb-1Order Number/Text Text classNametext-base font-bold text-gray-800 m-0#{orderNumber}/Text /Column Column Text classNametext-xs text-gray-500 uppercase mb-1Order Date/Text Text classNametext-base font-bold text-gray-800 m-0{orderDate.toLocaleDateString()}/Text /Column /Row /Section Hr classNameborder-gray-200 my-6 / Heading ash2 classNametext-xl font-bold text-gray-800 my-4 Order Items /Heading {items.map((item, index) ( Section key{index} classNamemb-4 Row Column classNamew-20 align-top Img src{item.image} alt{item.name} width80 height80 classNamerounded border border-gray-200 / /Column Column classNamealign-top pl-4 Text classNametext-base font-bold text-gray-800 m-0 mb-1{item.name}/Text {item.sku Text classNametext-sm text-gray-400 m-0 mb-2SKU: {item.sku}/Text} Text classNametext-sm text-gray-500 m-0 Quantity: {item.quantity} × ${item.price.toFixed(2)} /Text /Column Column classNamew-24 text-right align-top Text classNametext-base font-bold text-gray-800 m-0 ${(item.quantity * item.price).toFixed(2)} /Text /Column /Row /Section ))} Hr classNameborder-gray-200 my-6 / Section classNamemt-6 Row ColumnText classNametext-sm text-gray-500 my-2Subtotal/Text/Column Column classNametext-right Text classNametext-sm text-gray-800 my-2${subtotal.toFixed(2)}/Text /Column /Row Row ColumnText classNametext-sm text-gray-500 my-2Shipping/Text/Column Column classNametext-right Text classNametext-sm text-gray-800 my-2${shipping.toFixed(2)}/Text /Column /Row Row ColumnText classNametext-sm text-gray-500 my-2Tax/Text/Column Column classNametext-right Text classNametext-sm text-gray-800 my-2${tax.toFixed(2)}/Text /Column /Row Hr classNameborder-gray-200 my-3 / Row ColumnText classNametext-lg font-bold text-gray-800 my-2Total/Text/Column Column classNametext-right Text classNametext-lg font-bold text-gray-800 my-2${total.toFixed(2)}/Text /Column /Row /Section Hr classNameborder-gray-200 my-6 / Heading ash2 classNametext-xl font-bold text-gray-800 my-4 Shipping Address /Heading Section classNamebg-gray-50 p-4 rounded Text classNametext-sm text-gray-800 my-1{shippingAddress.name}/Text Text classNametext-sm text-gray-800 my-1{shippingAddress.street}/Text Text classNametext-sm text-gray-800 my-1 {shippingAddress.city}, {shippingAddress.state} {shippingAddress.zip} /Text Text classNametext-sm text-gray-800 my-1{shippingAddress.country}/Text /Section Text classNametext-sm text-gray-500 mt-8 Questions about your order? Reply to this email and well help you out. /Text /Container /Body /Tailwind /Html ); } OrderConfirmation.PreviewProps { orderNumber: 10234, orderDate: new Date(), items: [ { name: Vintage Macintosh, price: 499.00, quantity: 1, image: https://via.placeholder.com/80, sku: MAC-001 }, { name: Mechanical Keyboard, price: 149.99, quantity: 2, image: https://via.placeholder.com/80, sku: KEY-042 } ], subtotal: 798.98, shipping: 15.00, tax: 69.42, total: 883.40, shippingAddress: { name: John Doe, street: 123 Main St, city: San Francisco, state: CA, zip: 94102, country: USA } } as OrderConfirmationProps;该示例值得学习的写法商品卡片的行结构每个items.map项生成一个Section Row内部为图片栏w-20 align-top、信息栏align-top pl-4、右侧金额栏w-24 text-right align-top三Column布局。Column必须包裹在Row内使用见 COMPONENTS.md 的组件约束。宽度用百分比/固定像素组合左列固定w-2080px右列固定w-2496px中列自适应——比全部百分比更贴合图文混排的真实需求。align-top防止表格单元格默认垂直居中导致的三栏顶部错位。金额渲染纪律所有金额一律用.toFixed(2)保证两位小数输出右侧栏统一text-right与左侧文本右边界严格对齐避免小数点错位。数据接口扁平化与嵌套并用顶层 props 扁平展开金额字段shippingAddress用嵌套对象收纳地址sku设计为可选sku?: string用{item.sku ...}条件渲染保证无 SKU 商品也能正常展示。灰度卡片制造焦点订单号/日期信息块使用bg-gray-50 p-4 rounded的浅灰底与白底主卡片区分符合次要信息弱化的排版原则Preview中的动态值Order #{orderNumber}直接拼入预览摘要提升打开率。五、通知告警邮件CodeBlock 代码块与语义化严重级别配色DevOps/SRE 场景中部署失败/构建报错类通知需要在邮件正文中贴出日志。React Email 提供基于 Prism.js 的CodeBlock组件可选主题与行号配合 severity 驱动的动态配色可以做出专业告警模板。文档原始实现如下import { Html, Head, Preview, Body, Container, Section, Heading, Text, CodeBlock, dracula, Hr, Link, Tailwind, pixelBasedPreset } from react-email/components; interface NotificationProps { title: string; message: string; severity: info | warning | error | success; timestamp: Date; logData?: string; actionUrl?: string; actionLabel?: string; } export default function Notification({ title, message, severity, timestamp, logData, actionUrl, actionLabel View Details }: NotificationProps) { const severityColors { info: bg-sky-500, warning: bg-amber-500, error: bg-red-500, success: bg-green-500 }; const severityBtnColors { info: bg-sky-500, warning: bg-amber-500, error: bg-red-500, success: bg-green-500 }; return ( Html langen Tailwind config{{ presets: [pixelBasedPreset] }} Head / Preview{title} - {severity}/Preview Body classNamebg-gray-100 font-mono Container classNamemx-auto max-w-xl bg-white border border-gray-200 rounded overflow-hidden Section className{h-1 w-full ${severityColors[severity]}} / Heading classNametext-2xl font-bold text-gray-800 mx-6 mt-6 mb-4 {title} /Heading Text className{inline-block px-3 py-1 text-xs font-bold text-white rounded-full mx-6 mb-4 ${severityBtnColors[severity]}} {severity.toUpperCase()} /Text Text classNametext-base leading-6 text-gray-800 mx-6 mb-4 {message} /Text Text classNametext-sm text-gray-500 mx-6 mb-6 {new Date(timestamp).toLocaleString(en-US, { dateStyle: long, timeStyle: short })} /Text {logData ( Hr classNameborder-gray-200 my-6 / Heading ash2 classNametext-lg font-bold text-gray-800 mx-6 my-4 Log Details /Heading Section classNamemx-6 CodeBlock code{logData} languagejson theme{dracula} lineNumbers / /Section / )} {actionUrl ( Hr classNameborder-gray-200 my-6 / Link href{actionUrl} className{inline-block px-6 py-3 text-base font-bold text-white rounded no-underline mx-6 mb-6 ${severityBtnColors[severity]}} {actionLabel} /Link / )} Hr classNameborder-gray-200 my-6 / Text classNametext-xs text-gray-500 mx-6 mb-6 This is an automated notification. Please do not reply to this email. /Text /Container /Body /Tailwind /Html ); } Notification.PreviewProps { title: Deployment Failed, message: The deployment to production environment has failed. Please review the logs and take corrective action., severity: error, timestamp: new Date(), logData: { error: Build failed, exit_code: 1, duration: 2m 34s, commit: abc123def }, actionUrl: https://example.com/deployments/123, actionLabel: View Deployment } as NotificationProps;该示例值得学习的写法severity 字典映射驱动整封邮件severity被限制为字面量联合类型info | warning | error | success。两个颜色字典顶部色条/按钮与胶囊徽章同色系把语义等级翻译为 Tailwind 类名保证顶部色条、徽章与操作链接颜色三者一致。注意作者保留了同色的两套字典变量便于将来让按钮采用独立强调色。font-mono语境整封告警邮件的Body使用等宽字体族font-mono与日志内容气质统一。CodeBlock用法code原始字符串、languagejson、theme{dracula}从react-email/components直接导出、lineNumbers开启行号。按照 COMPONENTS.md 与 SKILL.md 的提示CodeBlock 所属的Section外层理论上还应配overflow-auto容器防内边距溢出实践中可视宽度决定取舍。可选片段用组合 JSX{logData (.../)}与{actionUrl (...)}在内容缺失时自动整段隐藏配套标签/分隔线也随之消失保证无日志或无跳转链接时邮件不出现空洞区域。日期本地化格式化new Date(timestamp).toLocaleString(en-US, { dateStyle: long, timeStyle: short })生成如 September 8, 2026 at 1:45 AM 的可读时间是邮件内展示时间戳的推荐做法。徽章用inline-blockrounded-full胶囊状 severity 徽章不占用整行与标题保持在同一视觉区块。六、多栏 Newsletter头条 双栏文章流 页脚退订Newsletter 是邮件版式复杂度最高的场景之一页眉 Logo、头条推荐、按行切分的双栏文章卡片、可点击Read article、以及必须包含物理地址与退订链接的页脚。以下文档原始实现展示了如何只用 Row/Column表格在邮件里还原响应式网格import { Html, Head, Preview, Body, Container, Section, Row, Column, Heading, Text, Img, Button, Hr, Link, Tailwind, pixelBasedPreset } from react-email/components; interface Article { title: string; excerpt: string; image: string; url: string; author: string; date: string; } interface NewsletterProps { articles: Article[]; unsubscribeUrl: string; } export default function Newsletter({ articles, unsubscribeUrl }: NewsletterProps) { return ( Html langen Tailwind config{{ presets: [pixelBasedPreset] }} Head / PreviewYour weekly roundup of the latest articles/Preview Body classNamebg-white font-sans Container classNamemx-auto max-w-xl {/* Header */} Section classNamept-10 px-5 pb-5 text-center Img srchttps://via.placeholder.com/150x50?textLogo altCompany Logo width150 height50 / /Section Heading classNametext-3xl font-bold text-gray-900 mx-5 mb-4 text-center This Weeks Highlights /Heading Text classNametext-base leading-6 text-gray-500 mx-5 mb-6 text-center Here are the top articles from this week. Enjoy your reading! /Text Hr classNameborder-gray-200 mx-5 my-8 / {/* Featured Article */} {articles[0] ( Section classNamepx-5 Img src{articles[0].image} alt{articles[0].title} width600 classNamew-full rounded-lg mb-4 / Heading ash2 classNametext-2xl font-bold text-gray-900 my-4 {articles[0].title} /Heading Text classNametext-base leading-6 text-gray-500 my-4 {articles[0].excerpt} /Text Text classNametext-sm text-gray-400 my-2 By {articles[0].author} • {articles[0].date} /Text Button href{articles[0].url} classNamebg-blue-600 text-white px-6 py-3 rounded font-bold inline-block no-underline Read More /Button /Section )} Hr classNameborder-gray-200 mx-5 my-8 / {/* Two-Column Articles */} {articles.slice(1, 5).length 0 ( Heading ash2 classNametext-2xl font-bold text-gray-900 mx-5 my-4 More From This Week /Heading {Array.from({ length: Math.ceil(articles.slice(1, 5).length / 2) }).map((_, rowIndex) { const leftArticle articles[1 rowIndex * 2]; const rightArticle articles[2 rowIndex * 2]; return ( Section key{rowIndex} classNamepx-5 mb-6 Row {leftArticle ( Column classNamew-1/2 align-top px-1 Img src{leftArticle.image} alt{leftArticle.title} width280 classNamew-full rounded mb-3 / Heading ash3 classNametext-lg font-bold text-gray-900 my-3 {leftArticle.title} /Heading Text classNametext-sm leading-5 text-gray-500 my-2 {leftArticle.excerpt} /Text Link href{leftArticle.url} classNametext-sm text-blue-600 no-underline font-semibold Read article → /Link /Column )} {rightArticle ( Column classNamew-1/2 align-top px-1 Img src{rightArticle.image} alt{rightArticle.title} width280 classNamew-full rounded mb-3 / Heading ash3 classNametext-lg font-bold text-gray-900 my-3 {rightArticle.title} /Heading Text classNametext-sm leading-5 text-gray-500 my-2 {rightArticle.excerpt} /Text Link href{rightArticle.url} classNametext-sm text-blue-600 no-underline font-semibold Read article → /Link /Column )} /Row /Section ); })} / )} Hr classNameborder-gray-200 mx-5 my-8 / {/* Footer */} Section classNamebg-gray-50 p-8 mt-8 text-center Text classNametext-sm text-gray-500 my-2 Youre receiving this because you subscribed to our newsletter. /Text Link href{unsubscribeUrl} classNametext-sm text-blue-600 underline block my-2 Unsubscribe from this list /Link Text classNametext-sm text-gray-500 my-2 © 2026 Company Name. All rights reserved. /Text /Section /Container /Body /Tailwind /Html ); } Newsletter.PreviewProps { articles: [ { title: The Future of Web Development in 2026, excerpt: Exploring the latest trends and technologies shaping modern web development., image: https://via.placeholder.com/600x300, url: https://example.com/article-1, author: Jane Doe, date: Jan 15, 2026 }, { title: React Server Components Explained, excerpt: A deep dive into React Server Components and their benefits., image: https://via.placeholder.com/280x140, url: https://example.com/article-2, author: John Smith, date: Jan 14, 2026 }, { title: Building Accessible Web Apps, excerpt: Best practices for creating inclusive digital experiences., image: https://via.placeholder.com/280x140, url: https://example.com/article-3, author: Sarah Johnson, date: Jan 13, 2026 } ], unsubscribeUrl: https://example.com/unsubscribe } as NewsletterProps;该示例值得学习的写法头条 双栏的数据驱动articles[0]恒为头条区articles.slice(1, 5)取后续文章通过Math.ceil(length / 2)计算所需行数再用Array.from生成行每行内leftArticle articles[1 rowIndex * 2]、rightArticle articles[2 rowIndex * 2]取左右稿。这套索引运算让你传入任意长度的文章数组都能自动排版且缺失侧奇数文章自动留空不报错。Section Row Column三层结构还原两栏Column用w-1/2 align-top px-1等宽分栏左右卡片内联文章信息这是邮件客户端中唯一可靠的双列网格实现方式。Img显式宽高 圆角头条图width600且classNamew-full rounded-lg双栏图width280配合rounded/rounded-lg做圆角裁切文案中引用页眉 Logo 也显式给出width/height防止布局抖动。行内Read article →链接次要阅读入口用Linktext-blue-600→箭头弱化呈现与头条的实心ButtonRead More形成主次两级 CTA。合规页脚底部灰底区块包含说明性文案、Unsubscribe 退订链接与版权行。这与 SKILL.md 中页脚需包含实体地址、退订链接、当前年份的最佳实践一致商用模板可扩展为含邮寄地址。Head /与内容分节注释代码内用{/* Header */}、{/* Featured Article */}、{/* Footer */}注释划分布局段落提升长模板可维护性。七、团队邀请邮件角色信息卡与邀请有效期最后一个示例聚焦 B2B 协作场景被邀请人需要一眼看到谁邀请我、加入哪个团队、我被授予什么角色。角色信息用独立灰底卡片突出邀请链接的失效时间也需要明确告知。文档原始实现如下import { Html, Head, Preview, Body, Container, Section, Heading, Text, Button, Hr, Tailwind, pixelBasedPreset } from react-email/components; interface TeamInvitationProps { inviterName: string; inviterEmail: string; teamName: string; role: string; inviteUrl: string; expiryDays: number; } export default function TeamInvitation({ inviterName, inviterEmail, teamName, role, inviteUrl, expiryDays }: TeamInvitationProps) { return ( Html langen Tailwind config{{ presets: [pixelBasedPreset] }} Head / PreviewYouve been invited to join {teamName}/Preview Body classNamebg-gray-100 font-sans Container classNamemx-auto py-10 px-5 max-w-xl bg-white Heading classNametext-3xl font-bold text-gray-800 text-center mb-6 Youre Invited! /Heading Text classNametext-base leading-7 text-gray-800 my-4 strong{inviterName}/strong ({inviterEmail}) has invited you to join the{ } strong{teamName}/strong team. /Text Section classNamebg-gray-50 p-5 rounded border border-gray-200 my-6 Text classNametext-xs text-gray-500 uppercase font-bold mb-2Role/Text Text classNametext-lg font-bold text-gray-800 m-0{role}/Text /Section Text classNametext-base leading-7 text-gray-800 my-4 Click the button below to accept the invitation and get started. /Text Button href{inviteUrl} classNamebg-green-600 text-white px-7 py-3.5 rounded block text-center font-bold text-base my-6 no-underline Accept Invitation /Button Hr classNameborder-gray-200 my-6 / Text classNametext-sm text-gray-500 leading-5 my-2 This invitation will expire in {expiryDays} day{expiryDays 1 ? s : }. /Text Text classNametext-sm text-gray-500 leading-5 my-2 If you werent expecting this invitation, you can safely ignore this email. /Text /Container /Body /Tailwind /Html ); } TeamInvitation.PreviewProps { inviterName: John Doe, inviterEmail: johnexample.com, teamName: Acme Corp Engineering, role: Developer, inviteUrl: https://example.com/invite/abc123, expiryDays: 7 } as TeamInvitationProps;该示例值得学习的写法关键信息用信息卡片突出Role区块以bg-gray-50 p-5 rounded border border-gray-200呈现内部标签行text-xs uppercase font-bold全大写灰字微标签 数值行text-lg font-bold。这里的边框同时写了border与border-gray-200颜色符合 STYLING.md 关于邮件里必须写明边框样式border-solid 等、需要时重置其余三边的提醒模板作者在浅灰底上用 border rounded 勾勒卡片边界。行内强调用strong邀请人、邮箱、团队名内联加粗读者扫读时先抓这三个实体。CTA 全宽块级 品牌绿bg-green-600 ... block text-center no-underline团队协作场景的确认按钮普遍采用绿色系积极的语义色。有效期信息二段式先给过期天数{expiryDays} day{s}复数处理再补非预期邀请可忽略的安抚话术兼顾紧迫感与安全提示。Preview动态拼接团队名Youve been invited to join {teamName}让收件箱摘要直接携带团队上下文配合较高的邮件打开率。八、总结五种模式的可复用要点清单文档结尾把五个模式验证的共同点浓缩为一份清单可作为你自行开发新模板时的 checklistTailwind CSS 工具类负责全部视觉无需书写任何外部 CSS 文件配合Tailwind config可将bg-brand这类自定义色注入见 SKILL.md 中的theme.extend.colors用法。组件使用统一遵循pixelBasedPreset预设这是邮件端rem单位不可用前提下的标准配置。TypeScript 类型收口 props每个模板声明独立interface布尔/可选项显式标注如expiryHours?: number、sku?: string。.PreviewProps静态属性固化演示数据本地 dev server 与测试工具可无数据渲染。响应式布局全部基于 Section/Row/Column 表格语义实现多栏与对齐绝不使用 flexbox/grid 与媒体查询。模板覆盖现实高频场景密码重置、订单确认、告警通知、Newsletter、团队邀请可分别作为你所在产品对应邮件模板的起点。进一步的工程细节——安装方式create-email脚手架、email dev --dir emails预览命令、基础模板骨架、组件逐个用法可继续查阅本仓库的 .agents/skills/react-email/SKILL.md、references/COMPONENTS.md、references/STYLING.md、references/SENDING.md 与 references/I18N.md。如果你正在把 React Email 集成进实际发信链路也可以对照本仓库其他邮件渲染/模板相关模块的既有实现来对齐工程约束——但请务必以本文所继承的五套「标准答案」作为模板编写的业务骨架。【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表