结合 react-email 零成本定制邮件系统
前言
有两种常用的方式:
方式1 比较简单,但依赖自己的域名 TXT 等记录解析,可以直接参考官方文档进行配置。
由于笔者已经将邮件托管到了飞书,因此选择第二种方式。
使用 nodemailer 发送邮件
- 邮件管理界面获取邮件的 SMTP
# .env
EMAIL_HOST=smtp.feishu.cn
EMAIL_PORT=465
EMAIL_USER=support@domain.com
EMAIL_PASS=your smtp pass
EMAILDEFAULT_FROM=support@domain.com
export const emailConstants = {
HOST: process.env.EMAIL_HOST!,
PORT: Number(process.env.EMAIL_PORT!),
USER: process.env.EMAIL_USER!,
PASS: process.env.EMAIL_PASS!,
EMAILDEFAULT_FROM: process.env.EMAILDEFAULT_FROM!
};
- 使用 nodemailer 发送邮件
import nodemailer from 'nodemailer';
import { emailConstants } from './constants';
export type CreateEmailSenderOptions = {
host: string;
port: number;
secure: boolean;
auth: {
user: string;
pass: string;
};
};
export type SendMailOptions = {
from?: string;
to: string;
body: string;
subject: string;
};
const transporter = nodemailer.createTransport({
host: emailConstants.HOST,
port: emailConstants.PORT,
secure: true,
auth: {
user: emailConstants.USER,
pass: emailConstants.PASS
}
});
export async function sendEmail({ from, to, body, subject }: SendMailOptions) {
return transporter.sendMail({
to,
subject,
from: from || emailConstants.EMAILDEFAULT_FROM,
html: body
});
}
使用 react-email 定制邮件模版
受限于 Cloudflare Worker 的运行时,nodemailer 还不支持运行在 Cloudlfare Worker 上,参考 Issue
- 推荐先使用 nextjs 初始化一个项目
- 手动安装 react-emial
{
"name": "email-app",
"scripts": {
"dev:email": "email dev",
},
"devDependencies": {
"react-email": "^3.0.1",
}
}
-
编写邮件模版
-
测试发送模版
import { render } from '@react-email/components';
import { sendEmail } from '@/libs/email';
const html = await render(<WelcomeEmail />)
sendEmail({
to: 'youremail@gmail.com',
subject: 'Welcome!',
body: html
});
使用 OpenAPI 构建独立的邮件服务
- 定义发送邮件路由
export const SendEmailRoute = createRoute({
tags: ['Email'],
method: 'post',
path: '/send-email',
request: {
body: {
content: {
'application/json': {
schema: z.object({
from: z.string().optional(),
to: z.string(),
subject: z.string(),
body: z.string()
})
}
}
}
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({
success: z.boolean()
})
}
},
description: 'SendEmailRoute'
}
}
});
- 路由实现
export function email(api: OpenAPIHono) {
api.openapi(SendEmailRoute, async c => {
const body = c.req.valid('json');
await sendEmail({
from: body.from,
to: body.to,
subject: body.subject,
body: body.body
});
return c.json(
{
success: true
},
200
);
});
}
参考: