Compare commits

...

2 Commits

Author SHA1 Message Date
Dream Hunter
c97a9a278b docs: clarify Address JWT vs User JWT and reorganize API menu (#914)
- Add warning notes in new-address-api and mail-api docs
- Explain the difference between Address JWT and User JWT
- Create dedicated 'API Endpoints' section in sidebar
- Update both zh and en documentation

Refs #910
2026-03-26 02:10:04 +08:00
Dream Hunter
a45d01f9fd feat: return address_id in /admin/new_address response (#913)
* feat: return address_id in /admin/new_address response

- Add address_id field to newAddress function return type
- Update CHANGELOG.md and CHANGELOG_EN.md

Fixes #912

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: verify address_id in new_address response

* fix: add address_id validation and improve test coverage

- Add null check for address_id after DB query
- Change address_id to required field in return type
- Add dedicated test for /admin/new_address endpoint
- Update e2e helper return type to non-optional

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 00:18:15 +08:00
12 changed files with 95 additions and 10 deletions

View File

@@ -10,6 +10,7 @@
### Features
- feat: |Admin API| `/admin/new_address` 接口返回值新增 `address_id` 字段,避免创建后需再次查询地址 ID#912
- feat: |自动回复| 发件人过滤支持正则表达式匹配,使用 `/pattern/` 语法(如 `/@example\.com$/`),同时保持前缀匹配的向后兼容
- feat: |Turnstile| 新增全局登录表单 Turnstile 人机验证,通过 `ENABLE_GLOBAL_TURNSTILE_CHECK` 环境变量控制(#767
- feat: |Telegram| Telegram 推送支持发送邮件附件(单文件限制 50MB多附件通过 `sendMediaGroup` 批量发送,通过 `ENABLE_TG_PUSH_ATTACHMENT` 环境变量开启(#894
@@ -26,6 +27,7 @@
### Docs
- docs: |API| 新增地址 JWT 与用户 JWT 的区分说明,避免混淆两种认证方式;调整文档菜单结构,将 API 接口文档归类到独立分组(#910
- docs: |Telegram| 新增每用户邮件推送和全局推送功能说明文档(#769
- docs: |Webhook| 新增 Telegram Bot、企业微信、Discord 等常用推送平台的 Webhook 模板示例
- feat: |Webhook| 前端预设模板新增 Telegram Bot、企业微信、Discord 三个模板

View File

@@ -10,6 +10,7 @@
### Features
- feat: |Admin API| `/admin/new_address` endpoint now returns `address_id` field, avoiding additional query after address creation (#912)
- feat: |Auto Reply| Add regex matching support for sender filter using `/pattern/` syntax (e.g. `/@example\.com$/`), backward compatible with prefix matching
- feat: |Turnstile| Add global Turnstile CAPTCHA for all login forms via `ENABLE_GLOBAL_TURNSTILE_CHECK` env var (#767)
- feat: |Telegram| Support sending email attachments in Telegram push (50MB per file limit), multiple attachments sent via `sendMediaGroup`, controlled by `ENABLE_TG_PUSH_ATTACHMENT` env var (#894)
@@ -26,6 +27,7 @@
### Docs
- docs: |API| Add clarification between Address JWT and User JWT to avoid confusion; reorganize documentation menu structure with dedicated API Endpoints section (#910)
- docs: |Telegram| Add per-user mail push and global push documentation (#769)
- docs: |Webhook| Add webhook template examples for Telegram Bot, WeChat Work, Discord and other common push platforms
- feat: |Webhook| Add Telegram Bot, WeChat Work, Discord preset templates to frontend webhook settings

View File

@@ -16,7 +16,7 @@ export async function createTestAddress(
ctx: APIRequestContext,
name: string,
domain: string = TEST_DOMAIN
): Promise<{ jwt: string; address: string }> {
): Promise<{ jwt: string; address: string; address_id: number }> {
const uniqueName = `${name}${Date.now()}`;
const res = await ctx.post(`${WORKER_URL}/api/new_address`, {
data: { name: uniqueName, domain },
@@ -25,7 +25,7 @@ export async function createTestAddress(
throw new Error(`Failed to create address: ${res.status()} ${await res.text()}`);
}
const body = await res.json();
return { jwt: body.jwt, address: body.address };
return { jwt: body.jwt, address: body.address, address_id: body.address_id };
}
/**

View File

@@ -4,9 +4,10 @@ import { WORKER_URL, TEST_DOMAIN, createTestAddress, deleteAddress, requestSendA
test.describe('Address Lifecycle', () => {
test('create address, request send access, fetch settings, then delete', async ({ request }) => {
// Create address
const { jwt, address } = await createTestAddress(request, 'lifecycle-test');
const { jwt, address, address_id } = await createTestAddress(request, 'lifecycle-test');
expect(address).toContain('@' + TEST_DOMAIN);
expect(jwt).toBeTruthy();
expect(address_id).toBeGreaterThan(0);
// Request send access (creates address_sender row with DEFAULT_SEND_BALANCE)
await requestSendAccess(request, jwt);

View File

@@ -0,0 +1,19 @@
import { test, expect } from '@playwright/test';
import { WORKER_URL, TEST_DOMAIN } from '../../fixtures/test-helpers';
test.describe('Admin New Address', () => {
test('should return address_id in response', async ({ request }) => {
const uniqueName = `admin-test${Date.now()}`;
const res = await request.post(`${WORKER_URL}/admin/new_address`, {
data: { name: uniqueName, domain: TEST_DOMAIN },
});
expect(res.ok()).toBe(true);
const body = await res.json();
expect(body.address).toContain('@' + TEST_DOMAIN);
expect(body.jwt).toBeTruthy();
expect(body.address_id).toBeGreaterThan(0);
expect(typeof body.address_id).toBe('number');
});
});

View File

@@ -149,19 +149,25 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
items: [
{ text: 'AI Email Recognition', link: 'feature/ai-extract' },
{ text: 'Configure SMTP IMAP Proxy', link: 'feature/config-smtp-proxy' },
{ text: 'Send Email API', link: 'feature/send-mail-api' },
{ text: 'View Email API', link: 'feature/mail-api' },
{ text: 'Configure Subdomain Email', link: 'feature/subdomain' },
{ text: 'Configure Telegram Bot', link: 'feature/telegram' },
{ text: 'Configure S3 Attachments', link: 'feature/s3-attachment' },
{ text: 'Configure WASM Email Parser', link: 'feature/mail_parser_wasm_worker' },
{ text: 'Configure Webhook', link: 'feature/webhook' },
{ text: 'New Address API', link: 'feature/new-address-api' },
{ text: 'OAuth2 Third-party Login', link: 'feature/user-oauth2' },
{ text: 'Enhance with Other Workers', link: 'feature/another-worker-enhanced' },
{ text: 'Add Google Ads', link: 'feature/google-ads.md' },
]
},
{
text: 'API Endpoints',
collapsed: false,
items: [
{ text: 'New Address API', link: 'feature/new-address-api' },
{ text: 'View Email API', link: 'feature/mail-api' },
{ text: 'Send Email API', link: 'feature/send-mail-api' },
]
},
{
text: 'Feature Overview',
collapsed: false,

View File

@@ -149,19 +149,25 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
items: [
{ text: 'AI 邮件识别', link: 'feature/ai-extract' },
{ text: '配置 SMTP IMAP 代理服务', link: 'feature/config-smtp-proxy' },
{ text: '发送邮件 API', link: 'feature/send-mail-api' },
{ text: '查看邮件 API', link: 'feature/mail-api' },
{ text: '配置子域名邮箱', link: 'feature/subdomain' },
{ text: '配置 Telegram Bot', link: 'feature/telegram' },
{ text: '配置 S3 附件', link: 'feature/s3-attachment' },
{ text: '配置 worker 使用 wasm 解析邮件', link: 'feature/mail_parser_wasm_worker' },
{ text: '配置 webhook', link: 'feature/webhook' },
{ text: '新建邮箱地址 API', link: 'feature/new-address-api' },
{ text: 'Oauth2 第三方登录', link: 'feature/user-oauth2' },
{ text: '配置其他worker增强', link: 'feature/another-worker-enhanced' },
{ text: '给网页增加 Google Ads', link: 'feature/google-ads.md' },
]
},
{
text: 'API 接口',
collapsed: false,
items: [
{ text: '新建邮箱地址 API', link: 'feature/new-address-api' },
{ text: '查看邮件 API', link: 'feature/mail-api' },
{ text: '发送邮件 API', link: 'feature/send-mail-api' },
]
},
{
text: '功能简介',
collapsed: false,

View File

@@ -131,6 +131,14 @@ print(response.json())
## User Mail API
::: warning Note: User JWT vs Address JWT
This endpoint uses **User JWT** (obtained via `/user_api/login` or `/user_api/register`), with `x-user-token` header.
**Do not confuse with Address JWT**:
- Address JWT uses `Authorization: Bearer <jwt>` to access `/api/*` endpoints
- User JWT uses `x-user-token: <jwt>` to access `/user_api/*` endpoints
:::
Supports `address` filter
```python

View File

@@ -1,5 +1,19 @@
# Create New Email Address API
::: warning Note: Address JWT vs User JWT
This page describes **Address JWT**, which is different from **User JWT**:
- **Address JWT**: Returned when creating a mailbox via `/api/new_address` or `/admin/new_address`
- Use `Authorization: Bearer <jwt>` header
- Access `/api/*` endpoints (view mails, delete mails, etc.)
- **User JWT**: Obtained via `/user_api/login` or `/user_api/register`
- Use `x-user-token: <jwt>` header
- Access `/user_api/*` endpoints (user account management)
**Do not confuse these two JWT types!**
:::
## Create Email Address via Admin API
This is a `python` example using the `requests` library to send emails.

View File

@@ -131,6 +131,14 @@ print(response.json())
## user 邮件 API
::: warning 注意:用户 JWT vs 地址 JWT
此接口使用**用户 JWT**(通过 `/user_api/login``/user_api/register` 获得),使用 `x-user-token` header。
**请勿与地址 JWT 混淆**
- 地址 JWT 使用 `Authorization: Bearer <jwt>` 访问 `/api/*` 接口
- 用户 JWT 使用 `x-user-token: <jwt>` 访问 `/user_api/*` 接口
:::
支持 `address` 过滤
```python

View File

@@ -1,5 +1,19 @@
# 新建邮箱地址 API
::: warning 注意:地址 JWT vs 用户 JWT
本页面介绍的是**地址 JWT**,与**用户 JWT** 是两种不同的认证方式:
- **地址 JWT**:通过 `/api/new_address``/admin/new_address` 创建邮箱时返回
- 使用 `Authorization: Bearer <jwt>` header
- 用于访问 `/api/*` 接口(查看邮件、删除邮件等)
- **用户 JWT**:通过 `/user_api/login``/user_api/register` 获得
- 使用 `x-user-token: <jwt>` header
- 用于访问 `/user_api/*` 接口(用户账户管理)
**请勿混淆两种 JWT 的使用方式!**
:::
## 通过 admin API 新建邮箱地址
这是一个 `python` 的例子,使用 `requests` 库发送邮件。

View File

@@ -168,7 +168,7 @@ export const newAddress = async (
enableCheckNameRegex?: boolean,
sourceMeta?: string | undefined | null,
}
): Promise<{ address: string, jwt: string, password?: string | null }> => {
): Promise<{ address: string, jwt: string, password?: string | null, address_id: number }> => {
const msgs = i18n.getMessagesbyContext(c);
// trim whitespace and remove special characters
name = name.trim().replace(getNameRegex(c), '')
@@ -247,6 +247,10 @@ export const newAddress = async (
`SELECT id FROM address where name = ?`
).bind(name).first<number>("id");
if (!address_id) {
throw new Error(msgs.FailedCreateAddressMsg);
}
// 如果启用地址密码功能,自动生成密码
const generatedPassword = await generatePasswordForAddress(c, name);
@@ -259,6 +263,7 @@ export const newAddress = async (
jwt: jwt,
address: name,
password: generatedPassword,
address_id: address_id,
}
}