给自己搭了个临时邮箱:Cloudflare + cloudflare_temp_email 完整教程
注册网站、收验证码、试新服务的时候,总有些场合不想掏出自己的常用邮箱:给出去容易,收回来的广告和泄露风险可不容易。公共临时邮箱网站倒是多,但域名经常被目标网站拉黑,收件箱还是公开的,隐私约等于没有。
所以我用自己的域名搭了一个:项目是开源的 cloudflare_temp_email(部署时版本 v1.13.0),整套东西全部跑在 Cloudflare 上,不用服务器、不用自己维护邮件系统,常驻成本是零。现在它跑在 mail.akali.cc.cd,随便生成一个 [email protected] 就能收信。这篇把从零搭建的完整过程记下来,包括我踩的三个坑——有两个坑不提前知道,能卡你一晚上。
先说清楚:它是怎么工作的
临时邮箱最核心的动作只有一个:收信。整条链路长这样:
1发件方 → 互联网邮件系统 → Cloudflare Email Routing(按域名的 MX 记录找过来)
2 → Catch-all 规则把所有地址的来信交给后端 Worker
3 → Worker 解析邮件,元数据和内容存进 D1(SQLite)/ KV
4你打开前端网页 → 调后端 Worker 的 API → 读出邮件列表和正文
对应到要创建的东西,一共四件:
| 组件 | 作用 | 在 Cloudflare 里是什么 |
|---|---|---|
| 后端 Worker | 收信处理、对外 API、管理后台 | Workers,名字 cloudflare-temp-email |
| D1 数据库 | 存邮箱地址、邮件元数据 | D1(SQLite),绑定名 DB |
| KV | 存邮件正文等大块数据 | Workers KV,绑定名 KV |
| 前端 | 用户打开的网页 | 一个静态站点(本文用另一个 Worker 托管,原因见坑 3) |
域名规划(以我的为例,全文都用这组域名讲解):
- 收信域名:
akali.cc.cd(生成的邮箱都是名字@akali.cc.cd) - 前端域名:
mail.akali.cc.cd - API 域名:
temp-email-api.akali.cc.cd(前端调它拿数据,你不用直接打开)
前置条件(先看这一节,能省一晚上)
- 一个 Cloudflare 账号,免费版就够全套跑起来;
- 一个域名,且域名的 DNS 必须托管在 Cloudflare(也就是 NS 指向 Cloudflare)。这是硬条件:收信靠 Cloudflare 的 Email Routing,它只服务 DNS 在自己家的域名;
- 这个域名不能正在用别的邮件服务。Email Routing 会接管域名的 MX 记录,域名原来如果挂着企业邮箱、Mailgun、网易邮箱之类的,要么换域名,要么别动它;
- 本地装好 Node.js + wrangler(
npm i -g wrangler),或者用项目的 GitHub Actions 部署方式,二选一。本文走 wrangler 手动路线,每一步都看得见,排错也方便。
坑 1 就出在这里:我最初选的域名是
akali.io,兴冲冲准备开工,一查才发现它的 NS 在 GoDaddy、邮件走的是 Mailgun——两个条件全不满足。最后换成了闲置的akali.cc.cd:NS 在 Cloudflare、没有任何 MX 记录,干净。动手之前先查一眼你域名的 NS 和 MX,别像我一样白忙活。
第一步:创建 D1 数据库和 KV
后端要一库一 KV,先建出来,等下写进 Worker 配置里。
控制台路线:Cloudflare 面板 → 存储和数据库 → D1,新建数据库,名字随意(我用的 temp-email-db);KV 同理,新建命名空间(我用的 temp-email-kv)。建完记下各自的 ID。
命令行路线(在项目目录里执行,后面会用到):
1npx wrangler d1 create temp-email-db
2npx wrangler kv namespace create temp-email-kv
命令会把 ID 打在输出里,同样记下来。
第二步:部署后端 Worker
2.1 拉代码、装依赖
1git clone https://github.com/dreamhunter2333/cloudflare_temp_email.git
2cd cloudflare_temp_email/worker
3npm install
4cp wrangler.toml.template wrangler.toml # 仓库里有模板,复制一份改
2.2 写 wrangler.toml(最关键的一步)
把模板改成下面这样(ID 和域名换成你自己的):
1name = "cloudflare-temp-email"
2main = "src/worker.ts"
3compatibility_date = "2024-09-23"
4compatibility_flags = [ "nodejs_compat" ]
5
6# 定时任务:每天清理一次过期数据
7[triggers]
8crons = [ "0 0 * * *" ]
9
10# 变量:你的邮箱域名等公开配置写这里
11[vars]
12DOMAINS = ["akali.cc.cd"] # 收信域名,可多个
13PREFIX = "tmp" # 随机生成地址时的默认前缀习惯,可留空
14ENABLE_USER_CREATE_EMAIL = true # 允许访客自助建邮箱
15ENABLE_USER_DELETE_EMAIL = true
16
17# D1 绑定:binding 名字必须叫 DB
18[[d1_databases]]
19binding = "DB"
20database_name = "temp-email-db"
21database_id = "<第一步记下的 D1 ID>"
22
23# KV 绑定:binding 名字必须叫 KV
24[[kv_namespaces]]
25binding = "KV"
26id = "<第一步记下的 KV ID>"
几个容易写错的点:
- 绑定名必须是
DB和KV,大小写都不能差,程序里是写死按这个名字找的; DOMAINS是 JSON 数组格式,域名要和后面 Email Routing 的域名完全一致;- 管理员密码和 JWT 密钥不要写进这个文件(它会进 git),用 secret 单独下发,见 2.3。
2.3 设置密钥
1# 管理员密码(可以设多个,JSON 数组),登录管理后台用
2npx wrangler secret put ADMIN_PASSWORDS
3# 粘贴:["一个够长够随机的密码"]
4
5# JWT 密钥,用户会话签名用,同样要长要随机
6npx wrangler secret put JWT_SECRET
7# 粘贴:<一段随机字符串>
2.4 部署并初始化数据库
1npx wrangler deploy
部署成功会给你一个 *.workers.dev 的临时地址。先别急着高兴,数据库还是空的,表都没建。用 wrangler 把仓库自带的建表脚本执行一遍:
1npx wrangler d1 execute temp-email-db --remote --file ../db/schema.sql
(不同版本仓库里 schema 文件的位置可能略有出入,以你拉到的版本为准;新版本也提供了在管理界面里初始化数据库的入口,二选一即可。)
验证一下后端活着:浏览器打开后端地址的 /health_check 路径,返回 OK 就说明 Worker 起来了。
2.5 给后端绑自定义域名
workers.dev 地址能用,但又长又难记,还可能被前端的跨域策略折腾。在面板里给这个 Worker 加自定义域名 temp-email-api.akali.cc.cd(Workers → 你的 Worker → 设置 → 域和路由 → 添加自定义域)。加上之后,前端就固定调这个地址。
第三步:部署前端
前端是仓库 frontend/ 里的一个 Vue 静态应用,先构建,构建时要告诉它后端在哪:
1cd ../frontend
2npm install
3# .env 里写一行(或直接环境变量传入):
4# VITE_API_BASE=https://temp-email-api.akali.cc.cd
5npm run build
6# 产物在 dist/ 目录
托管方式通常选 Cloudflare Pages:把 dist/ 传上去绑个自定义域名 mail.akali.cc.cd 就完事。但我没走通这条路:
坑 2:Pages 在我的账号上被整体拦了。 创建任何 Pages 项目都直接报错 “Subdomain is blocked”,不是配置问题,是账号层面的拦截,换个项目名重试也没用。如果你也撞上这个错,别在 Pages 上耗着,用下面的兜底方案。
兜底方案:再建一个 Worker,用 Workers 的静态资源(Static Assets)功能托管前端。新建一个小 Worker,它的配置只有两件事:把 dist/ 当静态资源发布、所有找不到的路径都回落到 index.html(前端是单页应用,深链接刷新不能 404):
1name = "akali-web"
2compatibility_date = "2024-09-23"
3
4[assets]
5directory = "./dist"
6not_found_handling = "single-page-application"
把 dist/ 拷到这个 Worker 的目录里,npx wrangler deploy,再给它绑自定义域名 mail.akali.cc.cd。效果和 Pages 一模一样,这个方案在我这儿一次通过。
第四步:打开 Email Routing(收信的最后一公里)
前面三步只是把系统搭好,这一步才是真正让邮件能寄进来:
- 面板打开
akali.cc.cd这个域名 → 电子邮件 → Email Routing → 启用; - 启用时 Cloudflare 会自动往域名 DNS 里加它自己的 MX 记录(
route1/2/3.mx.cloudflare.net三条)和一条 SPF 的 TXT 记录,别手贱去删,收信就靠它们; - 同页面的「路由规则」里找到 Catch-all(全部捕获),打开,动作选 Send to a Worker(发送到 Worker),目标选第二步的后端 Worker
cloudflare-temp-email,保存并确保状态是 Active。
Catch-all 的意思是:不管收件人是 [email protected] 还是 [email protected],只要域名对,所有来信统统交给 Worker。这正是临时邮箱需要的行为——地址可以现场随便编,不用预先在系统里建好。
坑 3:一个会让人虚惊的「待验证」。 Email Routing 里有个「目标地址」的概念,那是给「转发到某个真实邮箱」这种规则用的。如果按提示加了自己的邮箱当目标地址,它会一直显示 Pending(待验证),需要你去邮箱里点验证邮件。但 Catch-all 发给 Worker 这条路线根本不经过目标地址,临时邮箱功能不受它影响。看到 Pending 先别慌,确认你用的规则是发给 Worker 的就行;想消掉这个状态,去点那封验证邮件也可以。
第五步:实测收一封信
全链路验证,只认真实邮件:
- 打开前端
https://mail.akali.cc.cd,页面上会生成(或你手动新建)一个@akali.cc.cd的地址; - 用你的常用邮箱(我用的是 Outlook)给这个地址发一封测试信,标题正文随便写;
- 回到前端刷新收件箱——正常情况下几秒到几十秒内,邮件就会躺在列表里,点开能看到完整正文。
我部署完就是这样测的,测试信完好到达。以后拿它注册网站、收验证码,都是这个流程:现场开页面,地址复制走人,验证码到了刷新一下。
再顺手验一下管理后台:前端有管理入口,用 2.3 里设的管理员密码登录,能看全站的邮箱和邮件、做清理。这个密码就是整个临时邮箱的最高权限,别用弱口令,更别和别的网站重复。
费用与额度:为什么说常驻成本是零
这套东西全落在 Cloudflare 的免费额度里:Workers 免费版每天 10 万次请求,D1 和 KV 的免费容量对个人临时邮箱这种量级绰绰有余,Email Routing 本身免费。个人自用场景基本碰不到收费线。真正要留意的不是钱,是别把它开成公共服务到处宣传——收信量和滥用风险都会失控,域名还可能因为滥用被邮件系统拉黑。这东西最适合的定位就是:自己的域名、自己(和少数朋友)用。
日常维护
- 升级:上游更新挺勤的。升级就是拉新代码、重新
wrangler deploy后端和前端;注意版本更新说明里有没有新的数据库迁移脚本,有的话按说明对 D1 执行一遍; - 清理:Worker 里配的每日定时任务会清过期数据;管理后台也能手动删邮箱和邮件;
- 备份:邮件数据在 D1/KV 里。临时邮箱的定位本来就是「阅后即焚」,我没给它做备份;如果你在里面留了重要邮件,别指望它当保险箱,及时转存到常用邮箱;
- 换域名 / 加域名:把新域名按前置条件准备好(NS 在 Cloudflare、无在用 MX),在
DOMAINS变量里加上它,重新部署,再给新域名开一遍 Email Routing 的 Catch-all 即可,老域名不受影响。
坑汇总(速查)
- 域名 NS 不在 Cloudflare,或者 MX 被别的邮件服务占用 → Email Routing 这条路直接不通。动手前先查 NS 和 MX,闲置域名最省心;
- Pages 创建项目报 “Subdomain is blocked” → 账号级拦截,无解,别耗着,改用 Worker 静态资源托管前端,配置见第三步;
- Email Routing 目标地址一直 Pending → 只影响「转发到真实邮箱」的规则,Catch-all 发 Worker 不受影响;
- 前端打开了但收不到 / 列表空白 → 九成是前端构建时的
VITE_API_BASE写错(要指向 API 域名、带 https、末尾别多斜杠),或者后端自定义域名没绑好;先单独打开 API 域名的/health_check分段排查; - 邮件寄不进来 → 按顺序查:MX 记录是不是 Cloudflare 那三条 → Catch-all 是不是 Active 且指向对的 Worker → 后端 D1/KV 绑定名是不是
DB/KV。
最后
搭完最大的感受是:临时邮箱这种需求,自己有域名的话完全没必要用公共网站。自建版的域名是自己的,不会动不动被注册网站拉黑;收件箱只有自己能看;整套东西零成本躺在 Cloudflare 上,也不用惦记维护服务器。唯一要花的心思都在开工前——把域名条件确认好,后面就是顺水推舟。
成品在这儿,可以直接体验:mail.akali.cc.cd。搭建中遇到问题可以在下面留言,正好试试本站的评论区好不好用。