交易邮件 API 集成指南:注册验证、密码重置与通知系统
交易邮件(Transactional Email)是由用户操作触发的个性化邮件,如注册验证、密码重置、订单确认等。与营销邮件不同,交易邮件是用户"预期"收到的,因此打开率更高(通常在 70-90%),对送达率的要求也更高。
一、交易邮件 vs 营销邮件
| 特性 | 交易邮件 | 营销邮件 |
|---|---|---|
| 触发方式 | 用户操作触发 | 定时批量发送 |
| 个性化程度 | 高度个性化 | 中度个性化 |
| 打开率 | 70-90% | 20-30% |
| 发送频率 | 按需 | 定期 |
| 退订要求 | 不应包含营销退订链接 | 必须包含退订链接 |
| 送达要求 | 必须送达 | 尽量送达 |
二、常见交易邮件类型
2.1 注册验证
// 注册验证邮件 - 生成验证令牌
const crypto = require('crypto');
function generateVerificationToken(userId) {
const token = crypto.randomBytes(32).toString('hex');
const expiresAt = Date.now() + 24 * 60 * 60 * 1000; // 24 小时有效
// 保存到数据库
saveToken({ userId, token, expiresAt, type: 'email_verification' });
return token;
}
// 发送验证邮件
async function sendVerificationEmail(user) {
const token = generateVerificationToken(user.id);
const verifyUrl = `https://yourdomain.com/verify-email?token=${token}`;
await emailService.send({
to: user.email,
template: 'email-verification',
data: {
username: user.name,
verifyUrl,
expiresIn: '24 小时',
},
});
}
2.2 密码重置
// 密码重置流程
async function requestPasswordReset(email) {
const user = await findUserByEmail(email);
if (!user) {
// 不暴露用户是否存在(安全考虑)
return { success: true };
}
const token = crypto.randomBytes(32).toString('hex');
const expiresAt = Date.now() + 60 * 60 * 1000; // 1 小时有效
await saveToken({ userId: user.id, token, expiresAt, type: 'password_reset' });
const resetUrl = `https://yourdomain.com/reset-password?token=${token}`;
await emailService.send({
to: email,
template: 'password-reset',
data: {
username: user.name,
resetUrl,
expiresIn: '1 小时',
ipAddress: request.ip,
},
});
return { success: true };
}
2.3 订单通知
// 订单确认邮件
async function sendOrderConfirmation(order) {
await emailService.send({
to: order.customerEmail,
template: 'order-confirmation',
data: {
orderNumber: order.number,
customerName: order.customerName,
items: order.items.map(item => ({
name: item.name,
quantity: item.quantity,
price: formatPrice(item.price),
})),
total: formatPrice(order.total),
estimatedDelivery: order.estimatedDelivery,
trackingUrl: order.trackingUrl,
},
});
}
// 发货通知
async function sendShippingNotification(order) {
await emailService.send({
to: order.customerEmail,
template: 'shipping-notification',
data: {
orderNumber: order.number,
trackingNumber: order.trackingNumber,
trackingUrl: order.trackingUrl,
carrier: order.carrier,
estimatedDelivery: order.estimatedDelivery,
},
});
}
三、邮件模板管理
3.1 模板设计原则
- 每个场景一个模板:注册验证、密码重置、订单确认使用不同模板
- 模板参数化:使用占位符,避免硬编码
- 多语言支持:模板应支持国际化
- 响应式设计:适配移动端阅读
- 纯文本版本:同时提供 HTML 和纯文本版本
3.2 React Email 模板(Resend)
// Email 模板 - React Email
import { Html, Body, Container, Text, Link, Heading } from '@react-email/components';
export default function VerificationEmail({ username, verifyUrl }) {
return (
<Html>
<Body style={{ fontFamily: 'Arial, sans-serif' }}>
<Container>
<Heading>验证您的邮箱</Heading>
<Text>你好 {username},</Text>
<Text>感谢您注册!请点击下方按钮验证您的邮箱地址:</Text>
<Link href={verifyUrl} style={{
display: 'inline-block',
padding: '12px 24px',
background: '#0070f3',
color: 'white',
borderRadius: '5px',
}}>
验证邮箱
</Link>
<Text style={{ color: '#666', fontSize: '12px' }}>
此链接 24 小时内有效。如果您没有注册,请忽略此邮件。
</Text>
</Container>
</Body>
</Html>
);
}
四、系统设计
4.1 邮件队列架构
架构设计:
1. 应用服务 → 消息队列(Redis/RabbitMQ)→ 邮件 Worker → 邮件 API
↓
日志与监控
优点:
- 异步处理,不阻塞用户请求
- 重试机制,失败自动重试
- 限速控制,避免触发服务商限制
- 可水平扩展 Worker 数量
4.2 邮件发送服务
// 邮件服务抽象层
class EmailService {
constructor(provider) {
this.provider = provider; // SendGrid / Mailgun / Resend
}
async send({ to, template, data }) {
const email = await this.buildEmail(template, data);
try {
const result = await this.provider.send({
to,
from: '[email protected]',
subject: email.subject,
html: email.html,
text: email.text,
tags: [template], // 用于追踪
});
await this.logSuccess({ to, template, messageId: result.id });
return result;
} catch (error) {
await this.logError({ to, template, error: error.message });
throw error;
}
}
}
五、安全与防滥用
5.1 防止邮件轰炸
// 速率限制
const rateLimit = new Map();
function checkRateLimit(email, type) {
const key = `${email}:${type}`;
const now = Date.now();
const windowMs = 60 * 1000; // 1 分钟窗口
const maxAttempts = 3; // 最多 3 次
const attempts = rateLimit.get(key) || [];
const recentAttempts = attempts.filter(t => now - t < windowMs);
if (recentAttempts.length >= maxAttempts) {
return false; // 超出限制
}
recentAttempts.push(now);
rateLimit.set(key, recentAttempts);
return true;
}
5.2 令牌安全
- 使用安全的随机数生成器(
crypto.randomBytes) - 设置合理的过期时间
- 令牌使用后立即失效
- 记录失败尝试次数
六、监控与告警
6.1 关键监控指标
| 指标 | 告警阈值 | 说明 |
|---|---|---|
| 发送失败率 | > 3% | 邮件被拒绝或超时 |
| 延迟 | > 5 分钟 | 邮件发送到送达的延迟 |
| 退信率 | > 2% | 邮箱地址无效 |
| 队列积压 | > 1000 | 邮件队列堆积 |
6.2 日志记录
// 邮件日志结构
{
messageId: 'abc123',
to: '[email protected]',
template: 'password-reset',
status: 'delivered', // sent | delivered | opened | bounced | failed
timestamp: '2026-07-18T10:30:00Z',
latency: 350, // 毫秒
provider: 'sendgrid',
error: null,
}
七、总结
交易邮件是网站与用户沟通的命脉。设计交易邮件系统时,可靠性和送达率是首要考量。使用成熟的第三方邮件服务(Resend/SendGrid/Mailgun)是关键基础设施决策,配合邮件队列和重试机制确保可靠性。模板使用参数化设计,方便维护和国际化。最后,不要忘记监控——一个没人发现的邮件发送故障,比服务器宕机更隐蔽但后果同样严重。