diff --git a/CHANGELOG.md b/CHANGELOG.md index 97310daa..64295519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Features - feat: |Telegram| Telegram 新邮件推送与 `/mails` 历史邮件查看支持展示 AI 提取结果,包含验证码、验证链接、服务链接、订阅链接等关键信息 +- feat: |Webhook| 邮件 Webhook 模板支持填充 AI 提取结果占位符,包括 `aiExtractType`、`aiExtractResult`、`aiExtractResultText` - feat: |Frontend| 新增 `DISABLE_SHOW_GITHUB_FOR_USER` 配置,可仅对普通用户隐藏 Header 的 GitHub/版本入口,admin 仍可见(issue #1041) - feat: |Frontend| 将邮箱地址凭证弹窗升级为“地址凭证与连接方式”,复用普通用户与 admin 创建邮箱结果弹窗;支持通过 `ENABLE_AGENT_EMAIL_INFO` 展示 AI Agent 接入信息,并通过 `SMTP_IMAP_PROXY_CONFIG` 展示 SMTP/IMAP 客户端连接信息 - docs: |随机子域名| 在前端“启用随机子域名”提示与 `subdomain` / `worker-vars` 文档(中英)中明确说明:要让 `name@<随机>.abc.com` 真正收到邮件,必须在基础域名 DNS 中为 `*` 子域添加通配 MX 记录,Email Routing 子域不继承父域配置(issue #1035) diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index c4d92653..bb916cae 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -11,6 +11,7 @@ ### Features - feat: |Telegram| Show AI extraction results in Telegram new-mail notifications and `/mails` history views, including verification codes, auth links, service links, and subscription links +- feat: |Webhook| Support AI extraction placeholders in mail webhook templates, including `aiExtractType`, `aiExtractResult`, and `aiExtractResultText` - feat: |Frontend| Add `DISABLE_SHOW_GITHUB_FOR_USER` to hide the Header GitHub/version entry from normal users while keeping it visible to admin users (issue #1041) - feat: |Frontend| Upgrade the address credential dialog to "Address Credentials & Connection Methods" and reuse it for both normal users and admin-created addresses; support showing AI Agent access via `ENABLE_AGENT_EMAIL_INFO` and SMTP/IMAP client settings via `SMTP_IMAP_PROXY_CONFIG` - docs: |Random Subdomain| Clarify in the "Use Random Subdomain" frontend tip and the `subdomain` / `worker-vars` docs (zh & en) that receiving mail on `name@.abc.com` requires a wildcard `*` MX record under the base domain in DNS, because Cloudflare Email Routing does not inherit the apex configuration onto subdomains (issue #1035) diff --git a/e2e/tests/api/webhook-trigger.spec.ts b/e2e/tests/api/webhook-trigger.spec.ts index 54307e67..e82d7dcf 100644 --- a/e2e/tests/api/webhook-trigger.spec.ts +++ b/e2e/tests/api/webhook-trigger.spec.ts @@ -72,6 +72,9 @@ test.describe('Webhook — triggered on incoming mail', () => { from: '${from}', to: '${to}', subject: '${subject}', + aiExtractType: '${aiExtractType}', + aiExtractResult: '${aiExtractResult}', + aiExtractResultText: '${aiExtractResultText}', }), }, }); @@ -93,7 +96,16 @@ test.describe('Webhook — triggered on incoming mail', () => { ].join('\r\n'); const res = await request.post(`${WORKER_URL}/admin/test/receive_mail`, { - data: { from, to: address, raw }, + data: { + from, + to: address, + raw, + ai_extract_result: { + type: 'auth_code', + result: '654321', + result_text: 'Login verification code', + }, + }, }); expect(res.ok()).toBe(true); @@ -106,6 +118,9 @@ test.describe('Webhook — triggered on incoming mail', () => { expect(payload.from).toContain('webhook-sender@test.example.com'); expect(payload.to).toBe(address); expect(payload.subject).toBe(subject); + expect(payload.aiExtractType).toBe('auth_code'); + expect(payload.aiExtractResult).toBe('654321'); + expect(payload.aiExtractResultText).toBe('Login verification code'); } finally { server.close(); } diff --git a/vitepress-docs/docs/en/guide/feature/webhook.md b/vitepress-docs/docs/en/guide/feature/webhook.md index 79098362..e2073bf5 100644 --- a/vitepress-docs/docs/en/guide/feature/webhook.md +++ b/vitepress-docs/docs/en/guide/feature/webhook.md @@ -111,5 +111,10 @@ To get the url, you need to configure the worker's `FRONTEND_URL` to your fronte "raw": "${raw}", "parsedText": "${parsedText}", "parsedHtml": "${parsedHtml}", + "aiExtractType": "${aiExtractType}", + "aiExtractResult": "${aiExtractResult}", + "aiExtractResultText": "${aiExtractResultText}", } ``` + +When AI email extraction is enabled, webhook templates can use the `aiExtractType`, `aiExtractResult`, and `aiExtractResultText` placeholders. They are empty strings when no extraction result is available. diff --git a/vitepress-docs/docs/zh/guide/feature/webhook.md b/vitepress-docs/docs/zh/guide/feature/webhook.md index a2d93d2d..cfa15717 100644 --- a/vitepress-docs/docs/zh/guide/feature/webhook.md +++ b/vitepress-docs/docs/zh/guide/feature/webhook.md @@ -111,5 +111,10 @@ "raw": "${raw}", "parsedText": "${parsedText}", "parsedHtml": "${parsedHtml}", + "aiExtractType": "${aiExtractType}", + "aiExtractResult": "${aiExtractResult}", + "aiExtractResultText": "${aiExtractResultText}", } ``` + +启用 AI 邮件内容提取后,Webhook 模板可使用 `aiExtractType`、`aiExtractResult`、`aiExtractResultText` 占位符。未提取到结果时这些字段为空字符串。 diff --git a/worker/src/admin_api/mail_webhook_settings.ts b/worker/src/admin_api/mail_webhook_settings.ts index a854e2cc..e30c3075 100644 --- a/worker/src/admin_api/mail_webhook_settings.ts +++ b/worker/src/admin_api/mail_webhook_settings.ts @@ -37,7 +37,11 @@ async function testWebhookSettings(c: Context): Promise, address: string, parsedEmailContext: ParsedEmailContext, - message_id: string | null + message_id: string | null, + aiExtract?: ExtractResult | null ): Promise { if (!c.env.KV || !getBooleanValue(c.env.ENABLE_WEBHOOK)) { return @@ -843,6 +844,9 @@ export async function triggerWebhook( ).bind(address, message_id).first("id"); const parsedEmail = await commonParseMail(parsedEmailContext); + const usableAiExtract = aiExtract?.type !== "none" && aiExtract?.result + ? aiExtract + : null; const webhookMail = { id: mailId || "", url: c.env.FRONTEND_URL ? `${c.env.FRONTEND_URL}?mail_id=${mailId}` : "", @@ -852,6 +856,10 @@ export async function triggerWebhook( raw: parsedEmailContext.rawEmail || "", parsedText: parsedEmail?.text || "", parsedHtml: parsedEmail?.html || "", + aiExtract: usableAiExtract, + aiExtractType: usableAiExtract?.type || "", + aiExtractResult: usableAiExtract?.result || "", + aiExtractResultText: usableAiExtract?.result_text || "", } for (const settings of webhookList) { const res = await sendWebhook(settings, webhookMail); diff --git a/worker/src/email/index.ts b/worker/src/email/index.ts index 8593cd7d..e83f6f87 100644 --- a/worker/src/email/index.ts +++ b/worker/src/email/index.ts @@ -138,7 +138,7 @@ async function email(message: ForwardableEmailMessage, env: Bindings, ctx: Execu try { await triggerWebhook( { env: env } as Context, - toAddress, parsedEmailContext, message_id + toAddress, parsedEmailContext, message_id, aiExtractResult ); } catch (error) { console.error("send webhook error", error); diff --git a/worker/src/mails_api/webhook_settings.ts b/worker/src/mails_api/webhook_settings.ts index f22a8a03..496aba39 100644 --- a/worker/src/mails_api/webhook_settings.ts +++ b/worker/src/mails_api/webhook_settings.ts @@ -53,7 +53,11 @@ async function testWebhookSettings(c: Context): Promise