HTTP API 参考
语言与错误码
英文是默认语言。API、Web 控制台和通知渲染共用
internal/i18n/locales/ 下的内嵌文案,internal/i18n/languages.json
定义语言代码和本地名称。
| 代码 | 语言 |
|---|---|
en |
English |
zh-CN |
简体中文 |
zh-Hant |
繁體中文 |
ja |
日本語 |
ko |
한국어 |
de |
Deutsch |
fr |
Français |
es |
Español |
pt-BR |
Português (Brasil) |
-
首次访问按浏览器的
Accept-Language选择语言,切换后在本地保存规范代码。控制台语言与已保存的通知语言独立。 -
API(包括 App 管理接口)按
Accept-Language权重协商,返回Content-Language和Vary: Accept-Language。跳过不支持的偏好;缺省、非法或全部不支持时回退en,权重 0 的语言不参与协商。 -
地区别名映射到对应语言:
fr-CA→fr,es-MX→es,pt/pt-PT→pt-BR。中文区分字形:zh-Hans/zh-CN/zh-SG→zh-CN;zh-Hant/zh-TW/zh-HK/zh-MO→zh-Hant。显式字形优先于地区,单独zh使用简体。 -
GET /locales/default.json返回协商后的文案;GET /locales/{规范代码}.json返回指定文案;未知文案路径返回locale_not_supported。 -
通道设置
language独立控制哨站生成的通知,支持上述规范代码及地区别名,保存时归一化;省略或空值使用en,显式不支持的值返回 400config_language_invalid。请求语言不会覆盖该设置。 - Native 测试文案由推送中继服务根据配对设备语言生成,哨站通知语言不会覆盖它。推送中继服务和 App 各自支持相应的语言。
-
控制台本地化标准文件夹角色及常见名称。API 保留原始 IMAP
路径、自定义名称和
folder_roles,App 使用自己的文案翻译角色。通知标题继续使用原始文件夹末级名称;用户输入、邮件主题、正文和验证码保持原值。 -
文件夹扫描响应可包含
folder_names,按服务器层级分隔符将完整路径映射到末级名称。控制台显示“名称(完整路径)”,保存仍使用原始路径;分隔符未知时保留完整路径。Web 管理邮箱响应可包含已保存的folder_display(名称和角色),App 邮箱管理响应省略这份目录以保持文件夹权限边界。扫描期间配置变更返回 409settings_conflict;展示信息刷新保持配置 revision。 -
日志和 CLI 使用英文。业务错误保持稳定的英文
snake_case错误码与命名参数;存储保留代码和参数,展示层负责翻译。API 时间和数字保持原有机器可读格式,控制台按所选语言格式化时间。
{
"error": {
"code": "unauthorized",
"message": "请使用有效会话或 API Token 登录。"
}
}
投递记录的 last_error 与文件夹状态的
notice 使用相同的
{code, message, params?} 结构,例如
bark_http_error 搭配
{"status":"503"}。按
code 判断分支,message 用于展示。
每个邮箱的独立连接预算内预留 1
个名额给文件夹发现与连接测试。监听需求按“实时 Folder 数 +(存在定时
Folder 时的 1 个)”计算,最多使用
connection_limit - 1 个名额(默认 9
个);该邮箱所有操作的总连接数保持在
connection_limit(2–100)以内。已保存上限为 1 的配置按
configuration_invalid 降级启动,允许通过该邮箱的 PUT
接口修正。
connections_in_use
表示此刻实际占用的连接数,定时检查结束后会关闭共享连接。Web
邮箱列表显示配置所需的监听连接 / 总上限(例如 1 /
10);详情显示相同需求 / 监听容量(1 /
9),其中一个名额预留给管理操作。
HTTP API
GET /、静态资源和
/healthz 公开访问。首次设置完成前,其他管理接口统一返回
403 setup_required;POST /api/v1/setup
只能成功一次。设置后公开登录接口
POST /api/v1/session,其余接口使用会话 Cookie 或
Authorization: Bearer mwk_…。
Cookie 属性为 HttpOnly、SameSite=Strict、Path=/,TLS 连接或 HTTPS
Origin 加 Secure;空闲 7 天或绝对 30 天过期。Cookie 修改请求同时要求
X-CSRF-Token 和使用 HTTP 或 HTTPS、主机与端口和请求
Host 完全一致的 Origin。Bearer 请求免于
CSRF;显式提交错误的 Authorization 时,即使 Cookie 有效也拒绝请求。
登录和设置码失败按连接来源地址共享限额:15 分钟内 10
次失败,后续请求返回 429 too_many_attempts,Retry-After
为秒数。密码修改也使用该限额,来源由 Gin ClientIP
按上述可信代理网段解析。登录和设置请求中的跨站 Origin
会被拒绝。由于所有内网对端都被视为可信代理,局域网内的客户端可以伪造
X-Forwarded-For,把失败尝试分散到多个来源地址。不要把哨站监听端口暴露在不可信的局域网中,只通过反向代理对外提供访问。
JSON 请求体上限 64 KiB,未知字段或多余 JSON 返回 400。密码至少 12 个字符、最多 1024 个 UTF-8 字节;用户名及 Token 名称为 1–128 字节。管理 API 的时间戳统一为 UTC RFC 3339 字符串,包括投递 created_at/accepted_at、Token created_at/last_used_at、文件夹检查时间、日志时间和诊断生成时间;小数秒保留存储精度。未使用 Token 的 last_used_at 为 null,尚未接受的投递省略 accepted_at。计数、时长和 revision 保持数字。
POST /api/v1/session 的用户名或密码错误统一返回 401
login_credentials_invalid,提示“用户名或密码错误,请检查后重试。”;受保护接口缺少或使用无效凭证时返回
401 unauthorized。
设置码错误返回 400
setup_code_invalid,向导回到设置码步骤并保留用户名。PUT /api/v1/admin/password
的当前密码错误返回 400
current_password_invalid,仍计入失败限速,当前会话保持有效。登录失败与当前密码错误在原表单内提示并保留输入。
| 方法 | 路径 | 请求与响应 |
|---|---|---|
| POST | /api/v1/setup |
{"code":"XXXX-XXXX-XXXX","username":"admin","password":"…"};201,Cookie 与 csrf_token;重复设置返回 409
|
| POST | /api/v1/session |
{"username":"admin","password":"…"};200,Cookie 与 csrf_token
|
| GET | /api/v1/session |
返回
authenticated:true、csrf_token;Bearer 返回
method:"token"
|
| DELETE | /api/v1/session |
204,注销当前 Cookie 会话;需要会话鉴权 |
| PUT | /api/v1/admin/password |
{"current_password":"…","password":"…"};204,注销其他会话;Bearer 修改会注销全部会话
|
| POST | /api/v1/tokens |
{"name":"automation"};201,返回
id、name、created_at、last_used_at
和仅显示一次的 token
|
| GET | /api/v1/tokens |
{"tokens":[…]},仅元数据 |
| DELETE | /api/v1/tokens/:id |
204,撤销 Token;重复撤销仍返回 204 |
| GET | /api/v1/mailboxes |
{"mailboxes":[…]},邮箱脱敏视图列表
|
| POST | /api/v1/mailboxes |
使用下方邮箱表单创建;201,返回生成的 ID、revision 1 和脱敏视图 |
| GET / PUT / DELETE | /api/v1/mailboxes/:id |
读取 / 携带当前 revision 更新 / 删除(204);不存在返回 404
mailbox_not_found
|
| POST | /api/v1/mailboxes/test |
测试未保存的邮箱表单,返回
{"folders":[…]},保持配置原值
|
| POST | /api/v1/mailboxes/:id/test |
连接目标保持原值时合并该邮箱已保存的凭据后测试 |
| GET | /api/v1/mailboxes/:id/folders |
使用该邮箱预算发现可选文件夹 |
| GET / PUT | /api/v1/mailboxes/:id/subscriptions |
读取 / 按独立 revision 保存订阅;成功返回 202 |
| GET / PUT | /api/v1/settings/delivery |
读取 / 携带独立 revision 保存全局通道设置 |
| DELETE | /api/v1/settings/delivery |
携带
{revision} 清除通道与凭据;204,版本冲突409
|
| POST | /api/v1/settings/delivery/test |
合并已保存凭据并测试通道表单;204,保持配置原值 |
| GET | /api/v1/status |
文件夹状态、通道、投递计数及按作用域组织的 notices |
| GET | /api/v1/diagnostics |
下载脱敏 JSON 诊断报告,省略运行日志 |
| GET | /api/v1/logs |
鉴权后查询运行日志,支持 after、level、mailbox_id、limit(见下文) |
| GET | /api/v1/deliveries |
最近 50 条请求记录,包含标题和邮箱 / 文件夹摘要 |
| POST | /api/v1/test-push |
使用已保存配置发送测试,接受后返回 204,保持配置原值 |
| POST | /api/v1/deliveries/:id/retry |
重新处理 dead 任务,返回 202 |
投递记录的可选 message 对象包含
mailbox_id、mailbox_label、folder、subject(字符串或
null)和
test(布尔值)。名称按入队时保存,邮箱改名或删除后保持历史来源。subject
为 null 表示标题未保留,空字符串表示邮件无主题。
首次未配置通知时按“只提醒”保存;之后开启主题展示不会补回旧记录省略的标题。测试通知的
test=true,来源为空。摘要接口省略发件人和正文。
创建邮箱示例:
{
"label": "工作邮箱",
"host": "imap.example.org",
"port": 993,
"username": "user@example.org",
"password": "…",
"connection_limit": 10
}
最多保存 20 个邮箱,包含待修正的无效配置;继续创建返回 400
mailbox_limit_exceeded。ID 为
mbx_ 加随机串,创建后保持稳定。label
默认取 username(邮箱地址),最长 64 个 Unicode
字符,禁止换行。用户名超过 64
字符时需显式填写较短名称。更新时省略名称保留原值,空名称使用本次提交的
username。
邮箱 PUT 使用相同表单并携带 GET 读到的 revision,例如
"revision":1,必须填写
host、port、username。host、port、username 保持原值时,省略 password
保留原密码;显式空密码会被拒绝。省略
connection_limit 保留当前值;新邮箱默认 10,范围
2–100。创建 POST 省略 revision 或传 0。测试接口接受相同字段,无须
revision,保持配置原值;未保存邮箱的测试需要凭据,带 ID
的测试只合并该邮箱的已有凭据。
邮箱 GET 返回
id、label、revision、host、port、username、connection_limit、connections_in_use
与
"password":{"configured":true}。降级的无效邮箱返回 configured:false,保留 ID 和
revision 供修正。读取响应中的密码对象属于展示视图,不能作为写入值。
每个邮箱的连接预算独立。实时 Folder 各占一条连接,全部定时 Folder
合计占一条,需求最多为
connection_limit - 1,预留一条供管理。PUT
订阅及修改连接上限共用此公式,容量不足返回
connection_budget_exceeded。未保存邮箱的测试使用临时预算。未保存邮箱测试、已保存邮箱测试和文件夹发现三个入口还共用全局并发上限
2,超出立即返回 429
discovery_busy,结束或取消时释放名额。
首次保存通道示例:
{
"revision": 0,
"channel": "bark",
"preview": "off",
"retry_count": 0,
"language": "zh-CN",
"bark": { "endpoint": "https://api.day.app", "key": "…" }
}
每次更新前读取 /settings/delivery 并提交其
revision,首次保存从 0 增加到 1。Pushover 使用
pushover.token、pushover.user;Webhook
使用
webhook.url、webhook.secret。channel、preview、revision
必填;省略 language、retry_count 使用默认值。省略凭据(含 Webhook
URL)保留已保存值;修改 Bark 地址须显式提供设备
Key。显式空的当前通道凭据会被拒绝;GET 将凭据替换为
{"configured":true|false}。独立测试接口无须
revision。
邮箱创建和连接配置修改在保存前测试连接及登录。host、port、username、connection_limit
与现值相同且省略 password 时,PUT 只改 label:仍校验 revision
并保存,保持连接与进度,已入队通知保留原名称,之后入队使用新名称。创建或修改后的身份若与其他邮箱相同,返回
409 mailbox_duplicate;host 与 username
忽略大小写、port 精确匹配,同身份并发创建只成功一个。通道 PUT
对所有通道统一校验字段、地址、所选配对状态与
revision,直接保存,保存过程不发送测试或联系通道服务。显式通道测试保持配置原值,失败后仍可保存合法配置。邮箱网络测试在配置锁外执行,现有监听保持运行,邮箱测试失败保留原配置。设置
revision 过期返回 409
settings_conflict;邮箱测试期间订阅变化同样使快照失效,需重新读取后提交。各邮箱、全局通道分别维护
revision,修改不同邮箱、同时修改邮箱和通道互不冲突。
PUT 成功返回脱敏视图并立即生效。邮箱连接配置更新先停止自身监听,再保存并按需清理进度;存储失败恢复原监听,其他邮箱继续运行。通道变更时,进行中的请求沿用原快照,后续尝试使用新快照;尚未配置通道时队列保持待处理。
GET /api/v1/mailboxes/:id/subscriptions 返回
{"revision":1,"folders":[{"name":"INBOX","check":"realtime"},{"name":"Clients","check":"5m"}]}。PUT 提交读取到的 revision 与完整 folders
数组,空数组取消该邮箱的全部订阅。名称在邮箱内唯一,INBOX
大小写统一,每项最多 4096 个 UTF-8 字节;每项 name、check
必填,check 为 realtime、5m 或 15m;缺失、非法 check
或旧字符串数组返回 400。连接需求使用上文公式。只改 check
保留进度和事件
ID,衔接新邮件补查;取消后重新订阅继续重建基线。保存成功返回 202
和下一个版本,旧版本返回 409
subscriptions_conflict。文件夹存在性由监听确认,邮箱离线时仍可取消订阅。存储失败返回
503,当前订阅保持不变。
/status.folders[] 每项包含
mailbox_id、mailbox_label 与
check。mode 为 idle、poll 或 scheduled;定时 Folder
另有 RFC 3339 时间 next_check(失败时为下次重试时间),实时 Folder
省略该字段。已保存配置的 JSON
或模型校验失败时,对应项降级为未配置,在
/status.notices 的 mailbox:<id> 或
delivery 下报告
configuration_invalid,可通过该项 PUT
修正。订阅超预算时仅暂停该邮箱,在
subscriptions:<id> 下报告
connection_budget_exceeded;减少订阅或提高预算后恢复。解密失败仍拒绝启动。
诊断白名单包含生成时间、构建/Go/平台信息、队列计数以及匿名邮箱和监听状态(含
check 与 mode)。mailboxes[].index 与
watches[].mailbox_index 对应本次报告的“邮箱 1、邮箱
2……”;邮箱内监听有独立的 index。邮箱条目包含配置及订阅
notice 的错误码。仅 imap_folder_rejected 可导出
watches[].response_code。报告省略邮箱
ID、显示名称、地址、主机、文件夹名、邮件内容、任务
ID、凭据及其他错误参数。
任务状态:pending 等待请求,accepted
通道接受请求,dead 本轮请求结束且记录失败。
运行日志
通过 docker compose logs -f core(或
docker logs <容器名>)查看 JSON stderr
日志。管理客户端可使用会话 Cookie 或 API Token
查询同一组运行事件:GET
/api/v1/logs?after=0&level=info&mailbox_id=mbx_example&limit=200。
内存环形缓冲保留最近 2000 条 Info/Warn/Error
日志,重启清空。after 是排除本身的非负序号;level 为
info/warn/error,包含指定级别及以上,默认 info;省略 mailbox_id
时包含全部邮箱和全局操作。limit 默认 200,范围 1–500。参数非法返回
400 logs_request_invalid。
{
"entries": [
{
"seq": 42,
"time": "2026-09-29T00:00:00Z",
"level": "info",
"message": "Folder connection established",
"attrs": {
"mailbox_id": "mbx_example",
"folder": "INBOX",
"mode": "idle",
"check": "realtime"
}
}
],
"next": 42,
"cleared_through": 0
}
下一次请求把 next 作为 after。达到页大小时 next 为最后返回序号;遍历完快照时为快照最大序号,过滤结果为空也推进。淘汰的日志从当前保留记录继续;重启导致 next 小于 after 时,将游标重置为 0。条目按序号升序返回。
日志包含邮箱/Folder 生命周期、基线与入队数量、投递尝试、配置变更和管理员操作,全局事件的 mailbox_id 为空。attrs 仅输出这些标量字段:mailbox_id、folder、mode、check、code、event_id、channel、attempt、duration_ms、http_status、next_attempt、backoff_seconds、count、revision、token_id、version、listen。http_status=0 表示未收到 HTTP 响应;token_id 为公开记录 ID,区别于 Token 完整值。密码、Token/会话值、设置码、发件人、主题、正文和凭据 URL 均省略;设置码那一行只输出到控制台。日志包含 Folder 名称,匿名诊断导出继续省略日志和名称。
文件夹扫描与管理员邮箱测试返回原始路径数组
folders,并可附带 folder_roles:路径到
inbox、drafts、sent、trash、junk、archive、all
或 flagged 的映射。用途来自 IMAP SPECIAL-USE
属性,INBOX 按协议名称识别。Web
界面在缺少用途时,按常见英文文件夹名称进行忽略大小写的完整匹配;译名后用括号保留原始路径,其余名称保持原样。界面翻译不改变订阅路径。
通知标题仅显示斜杠分隔路径的末级名称;结构化 folder
字段保留完整路径。App 邮箱测试继续仅返回连接状态。
GET /api/v1/session 在 Cookie 会话响应中返回
username,Token 鉴权响应保持原有结构。
App 接收设备
通知配置增加 native_pairing_id。native
渠道必须从
/api/v1/native/devices
选择一个有效配对;测试通知和新事件只投递给该设备。更新时省略此字段保留原选择;空选择返回
native_target_required,失效目标返回
native_target_unavailable。当前 native
目标撤销后,通道与 native_pairing_id 同时清空,revision
增加一次;其他目标和通道保留。已开始的投递保留原目标及撤销结果。状态同步、并发与重启规则见配对撤销同步。
App 授权页分别管理管理权限和推送权限,两者独立撤销。
Native 测试通知
哨站使用签名 POST /v1/pairing-tests,正文
{pairing_id,test_id};每次显式测试生成新的 UUID
test_id。推送中继服务生成固定内容并同步提交 APNs,无须 Native Push
权益。表单测试、App 已保存配置测试和
/api/v1/test-push 共用此调用链。测试独立于邮件
Outbox,不自动重试。
仅推送中继服务返回 accepted 对应哨站 HTTP 204。APNs
拒绝、结果未知、sending
均返回本地化错误;推送中继服务限频映射为哨站 HTTP 429 并保留
Retry-After。安全日志记录推送中继服务 HTTP
状态与稳定错误码,省去响应正文、Token 和通知内容。哨站与 App
共享推送中继服务现有每设备每分钟、每主体每日额度及
(device_id,test_id)
幂等。用户再次点击测试会创建新的测试 ID。
正式邮件仍使用 /v1/push 并校验权益,事件 ID
或客户端测试标志均保持此规则。先部署支持配对测试接口的推送中继服务,再部署此版本哨站;哨站不回退到正式邮件接口。
清除投递记录与运行日志
-
DELETE /api/v1/deliveries返回200 {"deleted":N},永久清除全部历史中已结束的accepted/dead记录及关联 Native 记录。待投递/重试、Native 的 pending/queued/sending 状态、待执行的状态检查和活动更新会保留。清除失败记录后,其手动重试入口一并消失。邮箱检查点与配置保持原样。 -
DELETE /api/v1/logs返回200 {"cleared_through":N},清除所有级别、所有邮箱共享的内存日志。序号继续递增,标准错误/容器日志和导出文件保留。GET /api/v1/logs同时返回cleared_through;客户端先移除缓存中seq <= cleared_through的条目,再追加响应中的日志。 - 两个接口均要求管理员会话及 Origin/CSRF,或管理员 API Token。App 设备凭证无法执行这些操作。重复清除安全;操作完成后仍可产生新任务与新日志。
App 邮件正文
POST /api/v1/app/content
使用设备绑定的控制凭证与站主授予的 content 权限。请求为
{ "reference": <message_ref> },响应包含 text、truncated、可选的清洗后
html 和 has_remote_images。正文阅读免费。
正文可读后,使用相同凭证、权限和引用调用
POST /api/v1/app/content/read,将邮箱中的邮件标记为已读。成功返回 204 No Content 与
Cache-Control: no-store。仅获取正文保持邮箱原有已读状态。两个操作均核验当前授权、订阅文件夹、邮箱身份和邮件引用。
修改凭据目标
邮箱测试与保存时,修改 host、port 或
username
必须重新输入已保存的邮箱密码;省略、null、空白或无效替换密码返回 400
mailbox_password_required_for_change。修改 Bark
服务地址必须重新输入已保存的设备 Key,否则返回 400
bark_key_required_for_change,当前选择其他通道时同样执行。地址变化包含端口、路径和尾部斜杠变化;省略
Bark 地址保留原值。
拒绝请求会在连接或发送前结束,配置与 revision 保持原值。同一目标的其他设置修改可复用省略的凭据。显式提供凭据的测试保持已保存配置原值。读取响应继续只显示凭据是否已配置。
App 请求诊断
诊断导出使用 schema_version: 2,新增
app_requests:从共享的 2000 条内存日志中提取最近最多
300 条已完成的 App 请求。每条包含时间、服务端生成的
request_id(同时通过
X-Request-ID 返回)、路由模板、方法、HTTP
状态、耗时、阶段、结果与安全错误码。导出排除资源
ID、查询参数、凭证、签名引用、正文及完整运行日志。重启哨站或清空日志会移除这些记录,其他日志也可能挤出较旧请求。下载前会刷新报告。未到达哨站的请求仍需
App 诊断。
对于 POST /api/v1/app/content/read,哨站查询 UID 和
flags:已读直接成功,未读则标记后再次确认。STORE OK
本身无法证明邮件存在。UID 不存在、UIDVALIDITY
变化或文件夹明确不存在返回 404;服务商或权限失败返回 503,超时返回
504。远端引用失效时,本机缓存正文仍可阅读。
Markdown · AGPL-3.0-only · Mailwake 贡献者