如何在Next.js中用SSR React组件优化AWS SES模板邮件(结合Cron Jobs)?
可以用SSR React组件生成AWS SES邮件内容吗?当然可以,这是最佳实践方案
完全可以通过Next.js的服务端能力将React组件渲染成AWS SES兼容的邮件HTML,这种方式能充分复用你的React组件知识,实现模板的模块化、动态化,比维护静态模板高效得多。下面是具体的实现方案和示例:
核心思路
在Next.js的服务端环境(API路由、Server Component或定时任务脚本)中,将React邮件组件通过react-dom/server的renderToStaticMarkup方法渲染为纯静态HTML,再将该HTML传递给AWS SES发送。同时要注意邮件客户端的兼容性限制(比如必须用table布局、内联样式)。
具体实现步骤
1. 编写兼容邮件的React组件
邮件客户端对HTML/CSS的支持远不如浏览器,所以组件要遵循以下规则:
- 用table布局替代flex/grid
- 样式尽量内联(或用工具自动转内联)
- 避免客户端交互逻辑(如onClick)
- 不要使用复杂CSS选择器
示例组件components/EmailTemplate.tsx:
interface EmailTemplateProps { userName: string; content: string; actionLink: string; } export default function EmailTemplate({ userName, content, actionLink }: EmailTemplateProps) { return ( <table width="100%" cellpadding="0" cellspacing="0" border="0" style={{ fontFamily: 'Arial, sans-serif' }}> <tr> <td align="center" style={{ padding: '20px 0', backgroundColor: '#f5f5f5' }}> <table width="600" cellpadding="0" cellspacing="0" border="0" style={{ backgroundColor: '#fff', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }}> <tr> <td style={{ padding: '30px' }}> <h1 style={{ fontSize: '24px', color: '#333', margin: '0 0 20px' }}>您好,{userName}</h1> <p style={{ fontSize: '16px', color: '#666', lineHeight: '1.5', margin: '0 0 20px' }}>{content}</p> <a href={actionLink} style={{ display: 'inline-block', padding: '12px 24px', backgroundColor: '#0070f3', color: '#fff', textDecoration: 'none', borderRadius: '4px' }} > 立即处理 </a> <p style={{ fontSize: '14px', color: '#999', marginTop: '30px' }}>若您未操作此内容,可忽略本邮件</p> </td> </tr> </table> </td> </tr> </table> ); }
2. 服务端渲染组件并发送邮件
使用react-dom/server的renderToStaticMarkup生成HTML,再通过AWS SDK v3调用SES发送邮件。
安装依赖
npm install @aws-sdk/client-ses react-dom juice
(juice用于自动将style标签样式转为内联,简化样式维护)
定时任务逻辑(lib/cron-jobs.ts)
import { renderToStaticMarkup } from 'react-dom/server'; import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses'; import juice from 'juice'; import EmailTemplate from '@/components/EmailTemplate'; // 初始化AWS SES客户端 const sesClient = new SESClient({ region: process.env.AWS_REGION!, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID!, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, }, }); export async function sendScheduledNotification() { // 模拟从数据库/API获取动态数据 const dynamicData = { userName: '张三', content: '您的会员将于3天后到期,请及时续费', actionLink: 'https://your-app.com/renew' }; // 渲染组件为HTML,并自动内联样式 const rawHtml = renderToStaticMarkup(<EmailTemplate {...dynamicData} />); const emailHtml = juice(rawHtml); // 生成纯文本版本(提升邮件客户端兼容性) const emailText = `您好,${dynamicData.userName}\n\n${dynamicData.content}\n\n立即处理:${dynamicData.actionLink}\n\n若您未操作此内容,可忽略本邮件`; // 构造SES发送命令 const sendCommand = new SendEmailCommand({ Source: '您的发件邮箱 <noreply@your-domain.com>', Destination: { ToAddresses: ['user@example.com'], }, Message: { Subject: { Data: '会员到期提醒', Charset: 'UTF-8', }, Body: { Html: { Data: emailHtml, Charset: 'UTF-8', }, Text: { Data: emailText, Charset: 'UTF-8', }, }, }, }); try { await sesClient.send(sendCommand); console.log('定时邮件发送成功'); } catch (err) { console.error('定时邮件发送失败:', err); // 可添加告警逻辑,如发送到Slack或监控系统 } }
3. 配置next-schedule定时任务
在next.config.mjs中注册定时任务:
import { withScheduling } from '@vercel/scheduling'; export default withScheduling({ async schedule() { await import('./lib/cron-jobs').then(mod => mod.sendScheduledNotification()); }, scheduleOptions: { rule: '0 9 * * *', // 每天早上9点执行 }, });
关键注意事项
- AWS SES配置:必须在AWS控制台验证发件邮箱或域名,避免邮件被标记为垃圾邮件
- 兼容性测试:用AWS SES的测试邮箱或Ethereal工具测试渲染效果,重点兼容Outlook、Gmail等主流客户端
- 错误处理:定时任务中必须捕获异常,避免单次失败导致后续任务中断
- 性能优化:如果发送批量邮件,可缓存重复模板的渲染结果,减少重复计算
内容的提问来源于stack exchange,提问作者codernoob8
相关产品推荐
相关产品推荐

