自建临时邮箱全记录:用 Cloudflare 免费全家桶搭一个带邀请码的专属邮箱

自建临时邮箱全记录:用 Cloudflare 免费全家桶搭一个带邀请码的专属邮箱

临时邮箱这玩意,网上现成的服务一堆,但没有哪个是真正让人放心的:要么界面塞满广告,要么邮箱地址跟一万个人共享,要么哪天突然就没了。后来我想明白了,与其求人,不如自己搭一个。成本可以是零,数据在自己手里,想加什么规则加什么规则。

这套东西我用的是 dreamhunter2333/cloudflare_temp_email,一个把 Cloudflare 免费服务压榨到极致的项目。这篇文章把原理和完整搭建过程都写下来,也顺手记一下我踩过的坑,免得以后自己再踩一遍。

站点头图

一、它到底怎么跑起来的

先把原理说清楚,后面看配置才不会一头雾水。整个系统就四块砖头拼起来的:

邮件接收靠 Email Routing。 这是 Cloudflare 免费提供的收信能力。你在自己的域名上加几条 MX 记录,指到 Cloudflare 的邮件服务器,之后凡是寄到 任意前缀@你的域名 的邮件,都会先被 Cloudflare 拦截下来。你可以在后台设一条 Catch-all 规则,把所有这些邮件转发给一个 Worker 处理。Worker 就是一个跑在 Cloudflare 边缘节点上的函数,它拿到邮件的原文,做解析、存库,整个过程你一分钱都不用花。

邮件存 D1。 D1 是 Cloudflare 的 serverless SQLite,免费版每天能写 10 万行、读 500 万行、存 5GB。存几封临时邮件绰绰有余。项目把收到的邮件拆好存进十几张表里,谁来查都能秒出。

临时状态存 KV。 KV 是键值存储,这个项目拿它干两件事:一是存邮箱验证码(带 5 分钟过期时间),二是存各种运行期的设置项,比如黑名单、webhook 配置、用户系统开关。KV 免费版每天 10 万次读、1000 次写,因为写操作少,基本等于用不完。

对外发信靠 Resend。 这里要单独说一下。Cloudflare 免费版的原生发信能力(send_email binding)其实是 Workers 付费套餐才有的功能,白嫖党用不了。所以注册邮箱验证码这种"往外发邮件"的活,得交给第三方发信服务。我选的是 Resend,免费档每天 100 封,对个人临时邮箱完全够用。

前端就是一个 Vue 应用,跑在 Cloudflare Pages 上,跟 Worker 之间走 API 通信。前端负责界面,Worker 负责一切逻辑,两边都不用你自己买服务器。

二、完整搭建过程

下面按我实际操作的顺序来,每条命令都验证过。前提是你有一个托管在 Cloudflare 的域名,以及一个 Cloudflare 账号。

1. 准备工作

先把仓库克隆下来:

git clone https://github.com/dreamhunter2333/cloudflare_temp_email.git
cd cloudflare_temp_email/worker
pnpm install

需要 Node 环境和 pnpm,版本不要太老就行。

2. 建数据库并导入表结构

wrangler d1 create temp_email
wrangler d1 execute temp_email --remote --file=../db/schema.sql

第一条命令会返回一个 database_id,记下来,后面配置要用。第二条把建表的 SQL 灌进去,--remote 表示直接操作线上库,而不是本地模拟。

3. 写 wrangler.toml 并部署 Worker

这是最核心的一步。在 worker/wrangler.toml 里填上:

name = "xy-temp-mail"
main = "src/worker.ts"
compatibility_date = "2025-04-01"
compatibility_flags = ["nodejs_compat"]

[vars]
DEFAULT_LANG = "zh"
TITLE = "XY Temp Mail"
PREFIX = ""
DOMAINS = ["rwpt.ccwu.cc"]
DEFAULT_DOMAINS = ["rwpt.ccwu.cc"]
JWT_SECRET = "随便生成一串长字符串"
PASSWORDS = ["自己想个邀请码"]
ADMIN_PASSWORDS = ["管理后台密码"]
RESEND_TOKEN = "re_开头的那串"
DISABLE_ANONYMOUS_USER_CREATE_EMAIL = false

[[d1_databases]]
binding = "DB"
database_name = "temp_email"
database_id = "上一步拿到的id"

[[kv_namespaces]]
binding = "KV"
id = "稍后创建"

几个变量的含义稍微解释下。PREFIX 留空表示邮箱前缀完全自定义,想叫啥叫啥;设成 tmp 就变成 tmpxxxx 这种随机格式。PASSWORDS 是站点访问口令,设了之后任何人打开网站都要先输这个码,相当于一层邀请制。DOMAINS 和 DEFAULT_DOMAINS 填你要用的域名。

KV 需要先单独创建:

wrangler kv namespace create temp_email_kv

把返回的 id 填进上面的 id 字段,然后部署:

wrangler deploy

部署成功后,wrangler 会给你一个 xxx.xxx.workers.dev 的地址,这就是后端 API 的地址。

4. 构建并部署前端

进 frontend 目录:

cd ../frontend
echo "VITE_API_BASE=https://xy-temp-mail.你的账户.workers.dev" > .env.local
pnpm install
pnpm build

再创建一个 Pages 项目并上传:

wrangler pages project create temp-email --production-branch=main
wrangler pages deploy dist --project-name=temp-email --branch=main

部署完 Pages 会分配一个 xxx.pages.dev 地址。你想用好记的域名就再绑个自定义域,比如 mail.rwpt.ccwu.cc,在 Pages 项目的自定义域设置里加一条,或者手动在域名 DNS 里加一条 CNAME 指向那个 pages.dev 地址。

5. 打通收信:Email Routing

这一步必须手动在 Cloudflare 控制台操作,API 权限不够。

进控制台 → 选你的域名 → 左侧 Email → Email Routing,先开启这项服务,它会引导你加上 MX 记录,点上确认就行。然后进 Routes 规则,添加一条 Catch-all,Action 选 “Send to a Worker”,Worker 选你刚才部署的那个。

做完这一步,往 任意前缀@你的域名 发邮件,就会被 Cloudflare 接住并丢给 Worker 入库了。

6. 配置发信 + 开启注册邮箱验证

如果只是收邮件,到上一步就结束了。如果你的站点想开"注册账号"功能,并且要求注册时做邮箱验证,那还得配上发信。

先去 Resend 注册个账号,拿到 API key,填进 RESEND_TOKEN。然后在 Resend 后台添加你的域名并做 DNS 验证,它会给你三条记录(一条 SPF、两条 DKIM 之类),照抄到 Cloudflare 的 DNS 里。注意 DKIM 那条很长,别复制断了;另外 Resend 给的记录名带完整后缀,Cloudflare 里只填子域部分就行。

验证通过后,进你自己站点的管理后台(/admin),在用户设置里把"用户注册"和"邮箱验证"两个开关打开,再填一个验证码发件人地址,比如 verify@你的域名。

这里有个容易翻车的点:发信余额。这项目每个发件地址有独立余额,默认是 0,余额 0 就直接报"余额不足",验证码根本发不出去。要么在管理后台给 verify@你的域名 这个地址单独充点额度,要么像我一开始那样,在 wrangler.toml 里临时加一句 DEFAULT_SEND_BALANCE = "9999" 让新地址自动获得额度——不过这会顺带让所有新注册用户都能发信,不想要的话就只给 verify 地址单独充值,别用全局默认。

7. 门禁怎么设

项目原生支持几层门禁,按需开:

  • PASSWORDS:站点口令,所有人进站都要输,等于邀请制。
  • DISABLE_ANONYMOUS_USER_CREATE_EMAIL = true:禁止匿名建址,必须注册登录才能用。
  • 用户注册 + 邮箱验证码:在管理后台开,注册得留真邮箱收码。

我当时试过"必须注册"的模式,体验确实难受,又改回匿名可用了,只保留邀请码这一层挡人。具体怎么取舍看你自己。

三、我实际踩过的坑

这几个坑每个都卡了我一会儿,记下来省得重复付费。

Worker 名不能带下划线。 这是最大的一个坑。Cloudflare 的 Email Routing 里,Email Worker 的名字只允许字母、数字和连字符,带下划线它就在"Send to Worker"里找不到,规则一保存就报异常。我一开始起了个带下划线的名字,查了半天才定位到。起名一律用连字符,xy-temp-mail 这种。

keep_vars 会骗你。 如果你在 wrangler.toml 里开了 keep_vars = true,那么部署时,远端已经存在的环境变量不会被"你从本地删掉这行"这个动作清除掉。也就是说,你以为把某个变量删了,实际上它还在线上生效。想改值就老老实实写一行 变量 = false 显式覆盖,别指望删行。

PWA 插件在低配环境卡构建。 前端用 Vue + Vite,默认带了个 PWA 插件,会在构建结束时生成 Service Worker。在手机上的 proot 环境里,这个环节会因为 terser 卡死,构建直接失败。如果你也在低配环境构建,直接去 vite.config.js 里把这行插件注释掉,临时邮箱根本不需要离线缓存。

发信余额默认是 0。 前面已经提过,这里再强调一次。配好 Resend、开好验证码开关,结果发验证码报"余额不足",99% 是这个原因,先查 address_sender 表里那个发件地址的余额。

四、我自己的站点

折腾完这套,我的临时邮箱是:

目前只开了邀请码这一层,进站输码就能直接建地址收信,注册账号是可选项。整体就是个自用的小工具,图的是地址干净、数据在自己手上、想加功能随时能改。

如果你照着搭一遍卡在哪一步,可以先去看 Cloudflare 控制台里 Email Routing 的活动日志,那边会把邮件处理失败的原因列出来,比瞎猜快得多。