EasyStarter logoEasyStarter

邮件服务

配置 Resend 邮件服务,启用注册验证和密码重置邮件

邮件服务

EasyStarter 使用 Resend 作为邮件发送服务商,已内置以下两种系统邮件:

邮件类型发送时机
注册验证邮件用户注册后,需要点击链接激活账户
忘记密码邮件用户请求重置密码时,发送重置链接

注册 Resend 并获取 API Key

官方文档:Resend API Keys

  1. 前往 resend.com 注册账号
  2. 登录后进入 API Keys 页面
  3. 点击 Create API Key
  4. 填写 Key 名称,例如 easystarter-production
  5. 权限选择 Sending access(只需要发送权限即可)
  6. 点击 Add 完成创建
  7. 复制生成的 API Key(只展示一次,请立即保存)

复制出来的值就是 RESEND_API_KEY,格式以 re_ 开头,例如:

re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

验证发件人域名

Resend 要求你拥有一个已验证的域名,才能正式用于生产发送。

官方文档:Resend Domains

  1. 登录 Resend,进入 Domains 页面
  2. 点击 Add Domain
  3. 输入你的域名,例如 yourdomain.com
  4. Resend 会提供一组 DNS 记录(TXT、MX、DMARC 等)
  5. 前往你的域名 DNS 服务商(如 Cloudflare),按提示添加这些记录
  6. 回到 Resend,点击 Verify DNS Records,等待验证通过

验证通过后,发件人地址将使用 noreply@yourdomain.com 的格式(本地部分可配置)。

测试阶段:Resend 在免费版下允许向自己的注册邮箱发送邮件,无需验证域名即可测试。

填入 RESEND_API_KEY

RESEND_API_KEY 需要填入两个环境变量文件:

本地开发apps/server/.dev.vars):

apps/server/.dev.vars
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

生产部署apps/server/.env.production):

apps/server/.env.production
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

.env.production 用于通过 pnpm run secrets:bulk:production 批量推送到 Cloudflare Workers 的 Secrets,不会直接参与构建。

配置发件人地址

发件人地址在 packages/app-config/src/app-config.tscommon 配置块中定义:

packages/app-config/src/app-config.ts
common: {
  app: {
    name: "your-app-name",   // 邮件 From 展示名,改成你自己的产品名
    // ...
  },
  email: {
    provider: "resend",
    from: {
      localPart: "noreply",     // 发件人本地部分(@ 前面)
      domain: "yourdomain.com", // 已在 Resend 验证的域名
    },
  },
  // ...
},

最终发出的邮件 From 字段会由这两个字段自动组合为:

your-app-name <noreply@yourdomain.com>
  • your-app-name → 取自 common.app.name,修改为你自己的产品名即可
  • noreply@yourdomain.com → 由 email.from.localPart + @ + email.from.domain 拼接而成

确保 domain 与你在 Resend 中已验证的域名一致,否则会导致发送失败。

内置邮件模板

EasyStarter 使用 React Email 渲染邮件模板,模板源码位于:

apps/server/src/emails/templates/
├── sign-up-verify-email.tsx    # 注册验证邮件
└── forgot-password-email.tsx   # 忘记密码邮件

邮件内容均已支持多语言(i18n),会根据用户请求的语言自动切换。

如需自定义邮件样式或内容,直接修改对应的 .tsx 模板文件即可。

扩展其他邮件服务商

EasyStarter 的邮件层是基于 EmailProvider 接口设计的,只需四步即可接入任意服务商(如 SendGridPostmarkMailgun 等)。

第一步:扩展服务商类型

假设以 SendGrid 为例,在 packages/app-config/src/types.ts 中,将新服务商 key 追加到 SUPPORTED_EMAIL_PROVIDERS

packages/app-config/src/types.ts
export const SUPPORTED_EMAIL_PROVIDERS = ["resend", "sendgrid"] as const;

第二步:实现 Provider

apps/server/src/emails/providers/ 下新建文件,实现 EmailProvider 接口:

apps/server/src/emails/providers/sendgrid.ts
import type { EmailProvider, SendEmailParams } from "../types";

export function createSendGridEmailProvider(): EmailProvider {
  return {
    key: "sendgrid",
    async send({ from, to, subject, html, text }: SendEmailParams) {
      // 调用 SendGrid SDK 发送邮件
    },
  };
}

第三步:注册到邮件服务商中

apps/server/src/emails/index.tsproviders 对象中注册新 Provider:

apps/server/src/emails/index.ts
import { createSendGridEmailProvider } from "./providers/sendgrid";

const providers: Record<EmailProviderKey, EmailProvider> = {
  resend: createResendEmailProvider({ defaultFrom }),
  sendgrid: createSendGridEmailProvider(),
};

第四步:切换配置

packages/app-config/src/app-config.ts 中将 email.provider 改为新服务商的 key:

packages/app-config/src/app-config.ts
email: {
  provider: "sendgrid", // 切换到新服务商
  from: {
    localPart: "noreply",
    domain: "yourdomain.com",
  },
},

完成后,所有内置的发送函数(sendVerificationEmailsendResetPasswordEmail)都会自动通过新 Provider 发出,无需修改业务代码。