Worker 配置
配置 wrangler.toml、Cloudflare bindings、secrets、CORS 和生产环境安全项
Worker 配置分两类:
- 非敏感配置:写在
apps/worker/wrangler.toml,可以提交到仓库。 - 敏感配置:用
wrangler secret put写入 Cloudflare,不提交到仓库。

这是示意截图。开源仓库里不要提交真实 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 名称必须保持 DB 和 CACHE,代码会按这两个名字读取绑定。database_id、id 和 preview_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 也要配置到同一个域名或可接收该地址的域名。
4. 配置 Cookie 和 CORS
生产环境必须:
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.comAPI 也通过同一个域名下的 /api/... 访问:
https://mail.example.com/api/system/health则前端不需要设置 VITE_API_BASE_URL。这是当前代码的生产默认行为。
你需要在 Cloudflare 路由层把:
mail.example.com/api/*指向 Worker,把其他页面流量交给 Pages。
如果这条 route 写在 wrangler.toml 的 routes 里,GitHub Actions 使用的 CLOUDFLARE_API_TOKEN 还必须拥有目标 zone 的 Workers Routes: Edit 和 Zone: 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 productionOAuth 快捷登录
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:
- 发送
/newbot。 - 按提示填写 Bot 展示名称,例如
WeMail Staging。 - 按提示填写 Bot username,必须以
bot结尾,例如wemail_staging_bot。 - BotFather 会返回一串 token,格式类似
123456789:AA...。
保存这两个值:
| 值 | 示例 | 放在哪里 |
|---|---|---|
| Bot token | 123456789:AA... | TELEGRAM_BOT_TOKEN secret |
| Bot username | wemail_staging_bot | TELEGRAM_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 production7.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.comWebhook URL 固定是:
https://wemail-api.example.com/api/telegram/webhook部署完成并用管理员登录 WeMail 后,进入「Telegram」设置页,点击「配置 Webhook」。后台会用当前 API 域名自动调用 Telegram setWebhook,写入:
url: 当前 API origin +/api/telegram/webhookallowed_updates:message、channel_postdrop_pending_updates:truesecret_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"期望看到:
ok是true。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完成绑定:
- 点击生成绑定码。
- 如果已配置
TELEGRAM_BOT_USERNAME,页面会提供可直接打开的 deep link。 - 如果没有 deep link,把页面上的
/start wm_...命令复制到你的 Bot 对话里发送。 - 收到
Telegram 已绑定回复后,回到 WeMail 发送测试通知。
绑定码有效期是 15 分钟,只能使用一次。过期或已使用后重新生成即可。
7.7 验证通知链路
推荐按这个顺序检查:
curl "$API_BASE_URL/api/system/health"返回ok: true。getWebhookInfo里的 URL 指向当前环境。- WeMail 的 Telegram 页面显示 Bot 已配置。
- 用户绑定后订阅状态里能看到 Chat ID。
- 点击测试通知,Telegram 能收到消息。
- 在 Bot 对话里发送
/status,确认能收到当前账号与邮件状态。 - 收一封测试邮件,确认新邮件或识别结果通知能到达。
常见问题:
| 现象 | 检查点 |
|---|---|
| 页面没有 deep link | TELEGRAM_BOT_USERNAME 没有配置,或 username 带错了 |
| webhook 返回 401 | setWebhook 的 secret_token 和 TELEGRAM_WEBHOOK_SECRET 不一致 |
| 点击「配置 Webhook」失败 | 当前环境缺少 TELEGRAM_BOT_TOKEN,或 staging/production 缺少 TELEGRAM_WEBHOOK_SECRET,或 Bot token 属于另一个环境 |
| 绑定码一直无效 | 用户发送的不是当前页面生成的 /start wm_...,或绑定码已过期 |
测试通知显示 bot_not_configured | 当前 Worker 环境缺少 TELEGRAM_BOT_TOKEN |
测试通知显示 telegram_api_failed | Chat ID 无效、Bot 被用户拉黑,或 token 属于另一个 Bot |
| Bot 菜单没有出现命令 | 管理员尚未在 Telegram 设置页点击「配置 Bot 菜单」,或当前环境使用了错误的 Bot token |
| staging 设置后 production 失效 | 两个环境共用了同一个 Bot,后一次 setWebhook 覆盖了前一次 |
7.8 配置项速查
| 配置项 | 类型 | 必需 | 说明 |
|---|---|---|---|
TELEGRAM_BOT_TOKEN | Worker secret | 启用 Telegram 时必需 | BotFather 返回的 Bot token |
TELEGRAM_WEBHOOK_SECRET | Worker secret | staging/production 启用 Telegram 时必需 | 校验 Telegram webhook 请求头;除非 ENABLE_TELEGRAM=false |
TELEGRAM_BOT_USERNAME | Wrangler 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 里
ok是true。 environment分别是staging或production。
配置检查清单
- 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,已声明
ATTACHMENTSbinding。 -
curl /api/system/health返回正确环境。