白嫖CloudFlare建立自己的电子邮局

目标

  1. 创建属于自己的cloudflare邮箱系统
  2. 打开SMTP服务用于自己的系统

创建D1数据库

cloudflare→worker和pages→D1 SQL 数据库→创建
自己输入名称,地区选不选吧,理论上速度都差不多

然后在控制台下面的输入框输入
CREATE TABLE IF NOT EXISTS raw_mails (
  id INTEGER PRIMARY KEY,
  message_id TEXT,
  source TEXT,
  address TEXT,
  raw TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_raw_mails_address ON raw_mails(address);

CREATE TABLE IF NOT EXISTS address (
  id INTEGER PRIMARY KEY,
  name TEXT UNIQUE,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_address_name ON address(name);

CREATE TABLE IF NOT EXISTS auto_reply_mails (
  id INTEGER PRIMARY KEY,
  source_prefix TEXT,
  name TEXT,
  address TEXT UNIQUE,
  subject TEXT,
  message TEXT,
  enabled INTEGER DEFAULT 1,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_auto_reply_mails_address ON auto_reply_mails(address);

CREATE TABLE IF NOT EXISTS address_sender (
  id INTEGER PRIMARY KEY,
  address TEXT UNIQUE,
  balance INTEGER DEFAULT 0,
  enabled INTEGER DEFAULT 1,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_address_sender_address ON address_sender(address);

CREATE TABLE IF NOT EXISTS sendbox (
  id INTEGER PRIMARY KEY,
  address TEXT,
  raw TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_sendbox_address ON sendbox(address);

CREATE TABLE IF NOT EXISTS settings (
  key TEXT PRIMARY KEY,
  value TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS users (
  id INTEGER PRIMARY KEY,
  user_email TEXT UNIQUE NOT NULL,
  password TEXT NOT NULL,
  user_info TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_users_user_email ON users(user_email);

CREATE TABLE IF NOT EXISTS users_address (
  id INTEGER PRIMARY KEY,
  user_id INTEGER,
  address_id INTEGER UNIQUE,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_users_address_user_id ON users_address(user_id);

CREATE INDEX IF NOT EXISTS idx_users_address_address_id ON users_address(address_id);

CREATE TABLE IF NOT EXISTS user_roles (
  id INTEGER PRIMARY KEY,
  user_id INTEGER UNIQUE NOT NULL,
  role_text TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);

CREATE TABLE IF NOT EXISTS user_passkeys (
  id INTEGER PRIMARY KEY,
  user_id INTEGER NOT NULL,
  passkey_name TEXT NOT NULL,
  passkey_id TEXT NOT NULL,
  passkey TEXT NOT NULL,
  counter INTEGER DEFAULT 0,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_user_passkeys_user_id ON user_passkeys(user_id);

CREATE UNIQUE INDEX IF NOT EXISTS idx_user_passkeys_user_id_passkey_id ON user_passkeys(user_id, passkey_id);

workers后端

Workers 和 Pages→创建→创建worker→跳过编辑代码
去worker设置的 可观察性→运行时→兼容性标志添加

nodejs_compat

enter image description here

然后再下载这个js然后上传上去
再去设置里
如果你想用自己的域名就在‘域和路由’里添加一个域名(注意,这个域名是用于api的域名,不是用于登录web邮箱的域名
然后在’变量和机密’中添加变量

然后在控制台下面的输入框输入
配置项
TITLE# 自定义网站标题 “Custom Title”
PREFIX# 要处理的邮箱名称前缀,不需要后缀可配置为空字符串 “tmp”
MIN_ADDRESS_LEN # (min, max) adderss的长度,如果不设置,默认为(1, 30) 1
MAX_ADDRESS_LEN 30
ADDRESS_CHECK_REGEX “^(?!.admin).
ADDRESS_REGEX “[^a-z0-9]”
PASSWORDS# 如果你想要你的网站私有,添加密码 [“123”, “456”]
ADMIN_PASSWORDS# admin 控制台密码, 不配置则不允许访问控制台 [“123”, “456”]
DISABLE_ADMIN_PASSWORD_CHECK# admin 联系方式,不配置则不显示,可配置任意字符串 false
ADMIN_CONTACT "[email protected]"
DEFAULT_DOMAINS# 默认用户可用的域名(未登录或未分配角色的用户) [“xxx.xxx1” , “xxx.xxx2”]
DOMAINS# 你的域名, 支持多个域名 [“xxx.xxx1” , “xxx.xxx2”]
DOMAIN_LABELS# 对于中文域名,可以使用 DOMAIN_LABELS 显示域名的中文展示名称 [“中文.xxx”, “xxx.xxx2”]
USER_DEFAULT_ROLE# 新用户默认角色, 仅在启用邮件验证时有效 “vip”
ADMIN_USER_ROLE# admin 角色配置, 如果用户角色等于 ADMIN_USER_ROLE 则可以访问 admin 控制台 “admin”
USER_ROLES { domains = [“xxx.xxx1” , “xxx.xxx2”], role = “vip”, prefix = “vip” }
{ domains = [“xxx.xxx1” , “xxx.xxx2”], role = “admin”, prefix = “” }
JWT_SECRET# 用于生成 jwt 的密钥, jwt 用于给用户登录以及鉴权 “xxx”
BLACK_LIST# 黑名单,用于过滤发件人,逗号分隔 “”
ENABLE_USER_CREATE_EMAIL# 是否允许用户创建邮件, 不配置则不允许 true
ENABLE_USER_DELETE_EMAIL# 允许用户删除邮件, 不配置则不允许 true
ENABLE_AUTO_REPLY# 允许自动回复邮件 false
COPYRIGHT# 前端界面页脚文本 “Dream Hunter”
DISABLE_SHOW_GITHUB# 是否显示 GitHub 链接 true
DEFAULT_SEND_BALANCE# 默认发送邮件余额,如果不设置,将为 0 1
NO_LIMIT_SEND_ROLE# 可以无限发送邮件的角色 “vip”
CF_TURNSTILE_SITE_KEY# Turnstile 人机验证配置 “”
CF_TURNSTILE_SECRET_KEY# Turnstile 人机验证配置 “”
TG_MAX_ADDRESS# telegram bot 最多绑定邮箱数量 5
FORWARD_ADDRESS_LIST# 全局转发地址列表,如果不配置则不启用,启用后所有邮件都会转发到列表中的地址 [“[email protected]”]

这里说一下我的配置

ADMIN_PASSWORDS [“你的管理员密码”]
PASSWORDS [“网页登录密码,如果不需要私人网页那不用填这个”]
TITLE “网站标题”
DOMAINS [“你的域名”]
ENABLE_USER_CREATE_EMAIL true #允许发送邮件,不配置意味着不允许
ENABLE_USER_DELETE_EMAIL true #允许删除,不配置同理
JWT_SECRET “xxx” 不知道有什么用但是应该有用
PREFIX " " #要处理的邮箱名称前缀,不需要前缀可配置为空字符串

然后配置D1数据库
往下滑到 绑定→D1数据库
名称为 DB 值为你之前创建的数据库
然后访问网址,如果显示OK就执行下一步,如果不OK就看看是哪里出了问题

如果你要启用注册用户功能,并需要发送邮件验证,则需要创建 KV 缓存, 不需要可跳过此步骤
点击 Workers和Pages→KV→创建命名空间,名称随意
然后在刚才绑定数据库那里再绑定个KV空间就行
worker kv的变量名称要设置为大写的 KV ,否则无法识别(

配置邮件转发

  1. 配置对应域名的 电子邮件 DNS 记录, 如果是多个域名,需要配置多个域名的 电子邮件 DNS 记录
  2. 在将电子邮件地址绑定到您的 Worker 之前,您需要启用电子邮件路由并拥有至少一个经过验证的电子邮件地址。
  3. 配置每个域名的 Cloudflare Email Routing catch-all 发送到 worker

Pages前端

Wokers和Pages→创建→Pages→上传资产

  1. 这个页面里的‘输入地址’输入api网址,就是刚才workers里的https://xxx.aaa.dev或者你自己的域名,然后点击生成后下载压缩包后上传到这个pages
  2. 手动下载这个压缩包,修改压缩包里面的 index-xxx.js 文件 ,xx 是随机的字符串
    搜索 https://temp-email-api.xxx.xxx ,替换成你worker 的域名,然后压缩成新的zip文件,然后上传
    在自定义域里可以用自己的域名

配置发送邮件

  1. 使用 Cloudflare Workers 给已认证的邮箱发送邮件
    admin 后台 账号配置 已验证地址列表(可通过 cf 内部 api 发送邮件)
  2. 使用 resend 发送邮件
    注册 https://resend.com/domains 根据提示添加 DNS 记录,API KEYS 页面创建 api key
    在 cloudflare worker 页面的变量中添加 RESEND_TOKEN
    如果你有多个域名,对应不同的 api key,可以在变量中添加多个 secret, 名称为 RESEND_TOKEN_ + <. 换成 _ 的 大写域名>,例如你的域名为1.aaa.bbb和2.ccc.ddd
    RESEND_TOKEN_1_aaa_bbb key1
    RESEND_TOKEN_2_ccc_ddd key2

SMTP

如果你用了resend服务,直接用resend的就好
如果用cf的话建议看官方文档https://temp-mail-docs.awsl.uk/zh/guide/feature/config-smtp-proxy.html
不是因为我看不懂
绝对不是(
而且cf的smtp服务好像只能给同一个cf邮局内的邮件发送,所以还是用resend吧(

鸣谢


官方文档
github链接

Comment