WeMail Docs

Worker 配置

配置 wrangler.toml、Cloudflare bindings、secrets、CORS 和生产环境安全项

Worker 配置分两类:

  • 非敏感配置:写在 apps/worker/wrangler.toml,可以提交到仓库。
  • 敏感配置:用 wrangler secret put 写入 Cloudflare,不提交到仓库。

wrangler.toml 配置示意图

这是示意截图。开源仓库里不要提交真实 D1 / KV ID,生产部署由 GitHub Environment secrets 临时注入。

1. 理解环境结构

apps/worker/wrangler.toml 里有三块环境:

配置块用途
[vars]本地 wrangler dev 默认值
[env.staging]staging 远端部署
[env.production]production 远端部署

远端部署必须显式指定环境:

pnpm exec wrangler deploy --env staging
pnpm exec wrangler deploy --env production

当前 GitHub Actions 已经按这个方式执行。

2. 配置 D1 和 KV 绑定 ID

打开:

apps/worker/wrangler.toml

找到 staging:

[[env.staging.d1_databases]]
binding = "DB"
database_name = "wemail-staging"
database_id = "replace-with-staging-d1-id"

[[env.staging.kv_namespaces]]
binding = "CACHE"
id = "replace-with-staging-kv-id"
preview_id = "replace-with-staging-kv-preview-id"

找到 production:

[[env.production.d1_databases]]
binding = "DB"
database_name = "wemail-production"
database_id = "replace-with-production-d1-id"

[[env.production.kv_namespaces]]
binding = "CACHE"
id = "replace-with-production-kv-id"
preview_id = "replace-with-production-kv-preview-id"

binding 名称必须保持 DBCACHE,代码会按这两个名字读取绑定。database_ididpreview_id 在开源仓库里保持 replace-with-* 占位值。

把 Cloudflare 返回的真实 ID 配到 GitHub Environment secrets:

Secret说明
CLOUDFLARE_D1_DATABASE_ID当前环境的 D1 database ID
CLOUDFLARE_KV_NAMESPACE_ID当前环境的 KV namespace ID
CLOUDFLARE_KV_PREVIEW_NAMESPACE_ID当前环境的 KV preview namespace ID

当前 GitHub Actions 会在部署时把对应环境的占位值临时替换为这些 secrets,不会把真实 ID 写回仓库。

如果你完全手动部署,也可以只在本地临时替换,部署完成后不要提交真实 ID。

wrangler.toml 里的 RATE_LIMITER 使用 Cloudflare Workers Rate Limiting binding。它的 namespace_id 必须是账号内唯一的整数形式字符串,例如 staging 使用 1001、production 使用 1002;它不是需要创建或保密的 Cloudflare 资源 ID。只有当同一个 Cloudflare 账号里其他 Worker 已经使用了相同数字时,才需要换成别的整数。

3. 设置邮件域名

邮件域名现在由后台系统设置保存到 D1。Worker 首次启动时如果 D1 里还没有域名,会使用内置兜底值 example.com,方便本地开发先跑起来。

生产环境不要把真实域名写进开源仓库。部署完成并创建管理员账号后,进入 WeMail:

系统设置 -> 域名设置

把默认域名改成真实 Email Routing 域名,例如:

example.com

如果你用子域名收信,也可以填:

mail.example.com

这个值会影响用户创建邮箱账号时生成的地址。Email Routing 也要配置到同一个域名或可接收该地址的域名。

生产环境必须:

COOKIE_SECURE = "true"

CORS_ALLOWED_ORIGINS 要精确列出允许访问 Worker API 的前端来源:

CORS_ALLOWED_ORIGINS = "https://mail.example.com"

多个来源用英文逗号分隔:

CORS_ALLOWED_ORIGINS = "https://staging.example.com,https://mail.example.com"

不要用 *。WeMail 的浏览器请求使用 credentials: "include" 携带 session cookie,带 cookie 的跨域请求不能依赖通配符。

5. 决定前端和 Worker 的域名关系

WeMail 前端在生产构建中有两个模式。

模式 A:同域 /api 路由

如果前端访问:

https://mail.example.com

API 也通过同一个域名下的 /api/... 访问:

https://mail.example.com/api/system/health

则前端不需要设置 VITE_API_BASE_URL。这是当前代码的生产默认行为。

你需要在 Cloudflare 路由层把:

mail.example.com/api/*

指向 Worker,把其他页面流量交给 Pages。

如果这条 route 写在 wrangler.tomlroutes 里,GitHub Actions 使用的 CLOUDFLARE_API_TOKEN 还必须拥有目标 zone 的 Workers Routes: EditZone: Read 权限。否则 Worker 代码会上传成功,但 wrangler deploy 会在 Some triggers failed to deploy/zones/.../workers/routes 阶段失败。

模式 B:独立 Worker API 域名

如果 Worker API 是独立域名:

https://wemail-api.example.com

前端构建时必须设置:

VITE_API_BASE_URL=https://wemail-api.example.com pnpm build

同时 Worker 的 CORS_ALLOWED_ORIGINS 必须包含 Pages 域名:

CORS_ALLOWED_ORIGINS = "https://mail.example.com"

如果 OAuth callback 使用前端域名,但前端构建后的 API 请求会访问独立 API 子域名,还要让 session cookie 覆盖共同父域:

COOKIE_DOMAIN = ".example.com"

例如前端是 https://wemail.example.com、API 是 https://wemail-api.example.com 时,COOKIE_DOMAIN 应设为 .example.com。不要把这个值设成 workers.dev,也不要带 https:// 或路径。

production 建议使用同站 API 自定义域,例如 https://wemail-api.example.com,而不是长期使用 workers.dev。这样 Pages 和 Worker 仍在同一个站点下,登录 session cookie 更稳定。

如果你使用当前 GitHub Actions,需要把 VITE_API_BASE_URL 加到 build 环境中。详见 Pages 前端部署

6. 配置功能开关和额度

这些业务配置不需要写进 wrangler.toml。部署完成后用管理员账号进入后台维护,保存后写入 D1 的 system_settings 表,KV 只作为可失效缓存。

后台位置可配置内容
系统设置 -> 域名设置可用邮箱域名、默认域名、角色可用范围
系统设置 -> 业务默认值邮箱数量上限、邮件保留天数、默认每日发件额度、默认每日 API 调用额度、附件大小、AI fallback 次数
用户设置 -> 功能开关AI fallback、Telegram、发件、邮箱创建
用户设置 -> 配额单个用户的外发额度覆盖

新手部署建议:

  • 部署后先进入「系统设置」把域名改成真实 Email Routing 域名。
  • 在「域名设置」里填写新增域名后缀后,可以按 Enter 加入列表,也可以直接点击「保存域名设置」一次性保存。
  • 暂时不用发件、Telegram 或 AI 时,在「用户设置」的功能开关面板关闭对应能力。
  • 额度默认值先保守设置,确认真实使用量后再调大。

7. 写入 Worker secrets

进入 Worker 目录:

cd apps/worker

按实际启用的能力写入 secrets。

Resend 发件

如果启用外发邮件:

pnpm exec wrangler secret put RESEND_API_KEY --env staging
pnpm exec wrangler secret put RESEND_API_KEY --env production

可选设置默认发件地址:

pnpm exec wrangler secret put RESEND_FROM --env staging
pnpm exec wrangler secret put RESEND_FROM --env production

OAuth 快捷登录

GitHub 和 LinuxDo 快捷登录也通过 Worker secrets 启用。每个 provider 都必须配置 Client ID、Client Secret 和 callback URL 三项;缺任意一项时,该 provider 会返回 503。

详细步骤见 OAuth 快捷登录配置,其中包含 GitHub / LinuxDo 应用创建、回调地址选择、邀请码验收和常见错误排查。

Telegram

WeMail 的 Telegram 集成分两部分:

  • Worker 运行时配置:Bot token、Bot username、Webhook secret。
  • WeMail 后台配置:全局功能开关和用户自己的 Telegram 绑定。

推荐先在 staging 跑通,再复制到 production。

7.1 创建 Telegram Bot

打开 Telegram,搜索 @BotFather,按下面流程创建 Bot:

  1. 发送 /newbot
  2. 按提示填写 Bot 展示名称,例如 WeMail Staging
  3. 按提示填写 Bot username,必须以 bot 结尾,例如 wemail_staging_bot
  4. BotFather 会返回一串 token,格式类似 123456789:AA...

保存这两个值:

示例放在哪里
Bot token123456789:AA...TELEGRAM_BOT_TOKEN secret
Bot usernamewemail_staging_botTELEGRAM_BOT_USERNAME var

production 建议使用独立 Bot,例如 wemail_bot。不要让 staging 和 production 共用同一个 Bot,否则 webhook URL 会互相覆盖。

7.2 写入 Bot token

进入 Worker 目录:

cd apps/worker

写入 staging:

pnpm exec wrangler secret put TELEGRAM_BOT_TOKEN --env staging

粘贴 BotFather 返回的 token,回车确认。

写入 production:

pnpm exec wrangler secret put TELEGRAM_BOT_TOKEN --env production

7.3 配置 Bot username

TELEGRAM_BOT_USERNAME 不是强 secret,用来生成用户可直接打开的 Telegram deep link。把它写到 wrangler.toml 对应环境的 vars:

[env.staging.vars]
TELEGRAM_BOT_USERNAME = "wemail_staging_bot"

[env.production.vars]
TELEGRAM_BOT_USERNAME = "wemail_bot"

如果只做本地开发,也可以写在根 [vars]

[vars]
TELEGRAM_BOT_USERNAME = "wemail_local_bot"

不要带 @。代码会接受 @name,但文档和配置里统一写纯 username,排查时更清楚。

7.4 生成并写入 Webhook secret

Telegram 支持在 webhook 请求里带 X-Telegram-Bot-Api-Secret-Token 请求头。WeMail 会用 TELEGRAM_WEBHOOK_SECRET 校验这个请求头;staging/production 启用 Telegram 时必须配置,除非显式设置 ENABLE_TELEGRAM=false

生成一个随机值:

openssl rand -hex 32

分别写入 staging 和 production:

pnpm exec wrangler secret put TELEGRAM_WEBHOOK_SECRET --env staging
pnpm exec wrangler secret put TELEGRAM_WEBHOOK_SECRET --env production

每个环境可以使用不同的 secret。后面调用 Telegram setWebhook 时,secret_token 必须和当前环境的 TELEGRAM_WEBHOOK_SECRET 完全一致。

7.5 设置 Telegram webhook

先确认 Worker API 已经有可公网访问的 HTTPS 地址。推荐使用自定义 API 域名:

https://wemail-api.example.com

Webhook URL 固定是:

https://wemail-api.example.com/api/telegram/webhook

部署完成并用管理员登录 WeMail 后,进入「Telegram」设置页,点击「配置 Webhook」。后台会用当前 API 域名自动调用 Telegram setWebhook,写入:

  • url: 当前 API origin + /api/telegram/webhook
  • allowed_updates: messagechannel_post
  • drop_pending_updates: true
  • secret_token: 当前环境的 TELEGRAM_WEBHOOK_SECRET;staging/production 启用 Telegram 时必须和 Worker secret 完全一致

如果你使用独立 API 域名,请从这个独立域名进入后台或确保前端 API 请求实际打到这个域名。按钮成功后页面会显示写入的 webhook URL,确认它是你的公网 Worker API 域名即可。

也可以用 curl 手动设置 staging webhook:

export TELEGRAM_BOT_TOKEN="paste-staging-bot-token"
export TELEGRAM_WEBHOOK_SECRET="paste-staging-webhook-secret"
export API_BASE_URL="https://staging-wemail-api.example.com"

curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"${API_BASE_URL}/api/telegram/webhook\",
    \"secret_token\": \"${TELEGRAM_WEBHOOK_SECRET}\",
    \"allowed_updates\": [\"message\", \"channel_post\"],
    \"drop_pending_updates\": true
  }"

production 用 production Bot token、production webhook secret 和 production API 域名重复执行一次。

配置 Bot 菜单。进入「Telegram」设置页,点击「配置 Bot 菜单」即可把常用命令写入 Telegram 的命令菜单。

如果无法打开后台页面,也可以用管理员 session 手动调用接口:

curl -X POST "$API_BASE_URL/api/telegram/bot-menu" \
  -H "Cookie: wemail_session=<admin-session-cookie>"

该接口会调用 Telegram setMyCommands,并把 Bot 的 menu button 设置为 commands。菜单包含:

命令用途
/start使用后台生成的一次性绑定码绑定 WeMail
/help查看可用命令
/status查看账号与邮件状态
/accounts查看最近邮箱账号
/messages查看最近邮件
/pause暂停 Telegram 通知
/resume恢复 Telegram 通知
/test发送测试通知

检查 webhook 状态:

curl "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getWebhookInfo"

期望看到:

  • oktrue
  • result.url 是当前环境的 /api/telegram/webhook
  • last_error_message 为空或不存在。

如果要清空旧 webhook:

curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/deleteWebhook" \
  -H "Content-Type: application/json" \
  -d "{\"drop_pending_updates\": true}"

7.6 在 WeMail 后台启用 Telegram

部署 Worker 后,用管理员账号进入 WeMail:

用户设置 -> 功能开关

确认 Telegram 已开启。未配置 Bot token 时可以先关闭,避免用户看到可用但实际无法发送的通知入口。

然后普通用户或管理员进入:

Telegram

完成绑定:

  1. 点击生成绑定码。
  2. 如果已配置 TELEGRAM_BOT_USERNAME,页面会提供可直接打开的 deep link。
  3. 如果没有 deep link,把页面上的 /start wm_... 命令复制到你的 Bot 对话里发送。
  4. 收到 Telegram 已绑定 回复后,回到 WeMail 发送测试通知。

绑定码有效期是 15 分钟,只能使用一次。过期或已使用后重新生成即可。

7.7 验证通知链路

推荐按这个顺序检查:

  1. curl "$API_BASE_URL/api/system/health" 返回 ok: true
  2. getWebhookInfo 里的 URL 指向当前环境。
  3. WeMail 的 Telegram 页面显示 Bot 已配置。
  4. 用户绑定后订阅状态里能看到 Chat ID。
  5. 点击测试通知,Telegram 能收到消息。
  6. 在 Bot 对话里发送 /status,确认能收到当前账号与邮件状态。
  7. 收一封测试邮件,确认新邮件或识别结果通知能到达。

常见问题:

现象检查点
页面没有 deep linkTELEGRAM_BOT_USERNAME 没有配置,或 username 带错了
webhook 返回 401setWebhooksecret_tokenTELEGRAM_WEBHOOK_SECRET 不一致
点击「配置 Webhook」失败当前环境缺少 TELEGRAM_BOT_TOKEN,或 staging/production 缺少 TELEGRAM_WEBHOOK_SECRET,或 Bot token 属于另一个环境
绑定码一直无效用户发送的不是当前页面生成的 /start wm_...,或绑定码已过期
测试通知显示 bot_not_configured当前 Worker 环境缺少 TELEGRAM_BOT_TOKEN
测试通知显示 telegram_api_failedChat ID 无效、Bot 被用户拉黑,或 token 属于另一个 Bot
Bot 菜单没有出现命令管理员尚未在 Telegram 设置页点击「配置 Bot 菜单」,或当前环境使用了错误的 Bot token
staging 设置后 production 失效两个环境共用了同一个 Bot,后一次 setWebhook 覆盖了前一次

7.8 配置项速查

配置项类型必需说明
TELEGRAM_BOT_TOKENWorker secret启用 Telegram 时必需BotFather 返回的 Bot token
TELEGRAM_WEBHOOK_SECRETWorker secretstaging/production 启用 Telegram 时必需校验 Telegram webhook 请求头;除非 ENABLE_TELEGRAM=false
TELEGRAM_BOT_USERNAMEWrangler var推荐生成 https://t.me/... deep link
Telegram 功能开关后台设置启用 Telegram 时必需控制用户是否能使用 Telegram 通知

8. 可选:配置 R2 附件绑定

如果你已经创建 R2 bucket,可以在 wrangler.toml 加:

[[env.staging.r2_buckets]]
binding = "ATTACHMENTS"
bucket_name = "wemail-staging-attachments"

[[env.production.r2_buckets]]
binding = "ATTACHMENTS"
bucket_name = "wemail-production-attachments"

不配置 R2 时,入站邮件仍可保存附件元数据,但下载真实附件文件会受到限制。

9. 运行远端 migrations

GitHub Actions 会在部署 Worker 前自动执行:

pnpm exec wrangler d1 migrations apply wemail-staging --env staging --remote
pnpm exec wrangler d1 migrations apply wemail-production --env production --remote

如果你手动部署,也要先跑 migrations,再部署 Worker。

10. 验证 Worker

部署 staging 后:

curl -i "$STAGING_API_BASE_URL/api/system/health"

部署 production 后:

curl -i "$PRODUCTION_API_BASE_URL/api/system/health"

期望:

  • HTTP 200。
  • JSON 里 oktrue
  • environment 分别是 stagingproduction

配置检查清单

  • GitHub Environment secrets 已配置 D1 / KV 真实 ID。
  • apps/worker/wrangler.toml 没有提交真实 D1 / KV ID。
  • production 的 COOKIE_SECURE = "true"
  • 系统设置里的默认邮箱域名是真实收件域名。
  • CORS_ALLOWED_ORIGINS 包含真实前端域名。
  • 如启用 OAuth,GitHub / LinuxDo 的 Worker secrets 和回调地址已按 OAuth 快捷登录配置 完成。
  • D1、KV 的 staging / production ID 不混用。
  • 已通过 wrangler secret put 写入启用能力所需 secrets。
  • 如果启用 R2,已声明 ATTACHMENTS binding。
  • curl /api/system/health 返回正确环境。

On this page