Modoboa 2.11.1 管理 API 使用详解
以 curl 实测打通 Modoboa 2.11.1 REST API:Token 认证三途径、域名/账号/别名/参数端点 CRUD、开通场景一条龙、限流规则与 429/401/404 实测错误码。
Modoboa 2.11.1 管理 API 使用详解
目标:让运维/集成开发者用 curl 完成 Modoboa 的认证与全部日常管理动作——拿 Token、管域名、建账号、建别名、改平台参数,并理解限流与错误码。文中全部请求/响应均在 2.11.1 本地实例逐条实测照抄(2026-10-21),未实测的内容会明确标注来源。
一、环境信息
- 实测环境:Ubuntu 22.04.5 LTS,Modoboa 2.11.1(安装见同专栏《Ubuntu 22.04 安装 Modoboa 指南》),Nginx 监听 80,实例域名
mail.example.com - 实测时间:2026-10-21
- API 版本:
v2(当前主版本,OpenAPI 3.0.3 文档)与v1(旧版仍可用,本篇实测/api/v1/domains/返回 200);本文以 v2 为主 - 测试账号:超管
admin(SuperAdmins);示例域名example.com(已建)
二、API 能力总览
Modoboa 自带完整的 REST API(DRF 实现),是官方文档首页列出的三大卖点之一。三大入口:
| 入口 | 地址 | 用途 |
|---|---|---|
| OpenAPI 文档(JSON) | GET /api/schema-v2/ | 机读接口清单(实测:OpenAPI 3.0.3,标题 "Modoboa API",157 个路径) |
| Swagger UI | /api/schema-v2/swagger/ | 浏览器交互调试(实测 HTTP 200) |
| 旧版 API | /api/v1/... | 兼容旧集成(实测可用) |
能力域覆盖(与 157 个端点对应):域名管理(含 DKIM/DNS 体检)、账号与邮箱、别名、域管理员与权限、中继域、平台参数、日志与统计、告警、Webmail/日历/迁移(对应内置应用)等。
💡 技术拓展:Modoboa 的 API 与其面板共用同一套 DRF 序列化器与权限模型——面板前端(Vue SPA)本身就是一个 OAuth2 公共客户端,走授权码 + PKCE 流程调同一 API。因此"面板能做的,API 都能做",反过来也为自动化(开通、计费、工单系统)提供了与面板等价的能力面。
三、认证与鉴权
3.1 认证方式
settings.py 中 DEFAULT_AUTHENTICATION_CLASSES 配置了两类认证(2.11.1 实测文件):
- Token 认证(DRF authtoken):
Authorization: Token <key>头,本篇主线; - OAuth2(django-oauth-toolkit):面板 SPA 与第三方应用走
/api/o/的授权码 + PKCE 流程。
3.2 获取 Token(三种途径)
途径 A:管理命令生成(运维最常用,实测)
$ source /opt/modoboa/env/bin/activate && cd /home/modoboa/instance
$ python manage.py drf_create_token admin
Generated token 4ac64455dea0ba52d79a51b1bbb0a1b3b4f4ffd0 for user admin
途径 B:API 自助生成(超管专用端点,官方文档说明)
GET /api/v2/account/api_token/:读取当前超管已有 Token;POST /api/v2/account/api_token/:生成/重置 Token(仅超管可调用);- 面板路径:登录后进入 Settings → API 页面查看。
途径 C:OAuth2 应用授权:适合多用户/细粒度授权的集成,需在面板建立 OAuth2 应用后走标准授权码流程,本文不展开(见 swagger 中 /api/o/ 相关端点)。
3.3 带 Token 调用与鉴权模型
$ curl -s -H 'Host: mail.example.com' \
-H 'Authorization: Token 4ac64455dea0ba52d79a51b1bbb0a1b3b4f4ffd0' \
http://127.0.0.1/api/v2/account/me/ | head -c 400
{"date_joined":"2026-10-21T00:39:21.174547Z","language":"en","phone_number":null,
"secondary_email":null,"first_name":"","last_name":"","timezone":null,
"is_superuser":true,"is_active":true,"master_user":false,"username":"admin","role":"SuperAdmins","id":2}
不携带凭据的响应(实测):
$ curl -s http://127.0.0.1/api/v2/domains/ -w '\nstatus: %{http_code}\n'
{"detail":"Authentication credentials were not provided."}
status: 401
权限模型:SuperAdmins(全量)、DomainAdmins(仅辖内域名/身份)、SimpleUsers(仅自助信息)。API 与面板同规则——用域管理员 Token 调全局端点会被 403 拒绝。
四、核心资源端点精讲(全实测)
以下示例统一使用变量:BASE=http://127.0.0.1、头 Host: mail.example.com 与 Authorization: Token <TOKEN>(回显中省略重复的 curl 头部)。
4.1 域名:列表 / 创建 / 详情 / 删除
$ curl -s -H "$AUTH" "$BASE/api/v2/domains/"
{"count":1,"next":null,"previous":null,"results":[{"pk":1,"name":"example.com","quota":"0",
"default_mailbox_quota":"0","enabled":true,"type":"domain","enable_dkim":false,
"dkim_key_selector":"modoboa","dkim_key_length":null,"dkim_public_key":"",
"dkim_private_ke ...
$ curl -s -H "$AUTH" -H 'Content-Type: application/json' -X POST "$BASE/api/v2/domains/" \
-d '{"name":"example.com","type":"domain","enabled":true}' -w '\nstatus: %{http_code}\n'
{"pk":1,"name":"example.com","type":"domain",...,"dns_global_status":{"mx":false,"spf":false,
"dmarc":false,"autoconfig":false,"dkim":false,"dkim_spf_value":null,...}}
status: 201
💡 创建响应中的
dns_global_status即域名 DNS 体检结果(MX/SPF/DMARC/autoconfig/DKIM 各项布尔值),对应面板"域名详情 → DNS"页签;体检开关在平台参数 admin 组(enable_mx_checks、enable_spf_checks等,见同专栏配置参数详解 4.2 节)。
搜索/过滤(实测):
$ curl -s -H "$AUTH" "$BASE/api/v2/domains/?search=example"
{"count":1,"next":null,"previous":null,"results":[...]}
删除:DELETE /api/v2/domains/<pk>/(204)。
4.2 账号:创建(含邮箱)
账号创建必须带 password(实测缺省报错):
$ curl -s -H "$AUTH" -H 'Content-Type: application/json' -X POST "$BASE/api/v2/accounts/" -d '{"username":"jdoe@example.com","role":"SimpleUsers","mailbox":{"use_domain_quota":true}}' -w '\nstatus: %{http_code}\n'
{"password":["This field is required."]}
status: 400
正确请求(实测 201,且自动创建邮箱):
$ curl -s -H "$AUTH" -H 'Content-Type: application/json' -X POST "$BASE/api/v2/accounts/" \
-d '{"username":"jdoe@example.com","password":"Q1w2e3r4!","role":"SimpleUsers","mailbox":{"use_domain_quota":true}}' -w '\nstatus: %{http_code}\n'
{"pk":2,"username":"jdoe@example.com","first_name":"","last_name":"","is_active":true,"master_user":false,
"mailbox":{"pk":1,"use_domain_quota":true,"quota":"0","message_limit":null,"is_send_only":false},
"role":"SimpleUsers","language":"en","phone_number":null,"secondary_email":null,
"tfa_enabled":false,"totp_enabled":false,"webauthn_enabled":false,
"date_joined":"2026-10-21T01:50:57.039879Z","last_login":null}
status: 201
4.3 别名:创建与本地收件人校验
别名 recipients 必须指向已存在的本地收件人,否则 404(实测):
$ curl -s -H "$AUTH" -H 'Content-Type: application/json' -X POST "$BASE/api/v2/aliases/" \
-d '{"address":"postmaster@example.com","recipients":["admin@example.com"],"enabled":true}' -w '\nstatus: %{http_code}\n'
{"error": "Local recipient admin@example.com not found"}
status: 404
指向刚建的 jdoe@example.com 则成功(实测 201):
$ curl -s -H "$AUTH" -H 'Content-Type: application/json' -X POST "$BASE/api/v2/aliases/" \
-d '{"address":"postmaster@example.com","recipients":["jdoe@example.com"],"enabled":true}' -w '\nstatus: %{http_code}\n'
{"pk":3,"address":"postmaster@example.com","enabled":true,"recipients":["jdoe@example.com"],
"expire_at":null,"description":"","creation":"2026-10-21T01:50:57.164089Z","last_modification":"2026-10-21T01:50:57.164209Z"}
status: 201
4.4 身份聚合视图(账号+别名统一列表)
$ curl -s -H "$AUTH" "$BASE/api/v2/identities/?search=postmaster" | head -c 240
[{"pk":1,"type":"account","identity":"admin","name_or_rcpt":"----",
"tags":[{"name":"account","label":"account","type":"idt"},{"name":"SuperAdmins","label":"SuperAdmins","type":"grp"}],
"enabled":true,"possible_actions":[]},{"pk":2,"type":"ac ...
identities 把账号(type=account)与别名(type=alias)合并在一个可搜索列表里,对应面板"身份数量"页面;?search=、?type= 等查询参数同面板筛选。
4.5 平台参数
读取(实测节选):
$ curl -s -H "$AUTH" "$BASE/api/v2/parameters/global/core/" | head -8
{
"label": "General",
"params": {
"authentication_type": "local",
"password_scheme": "sha512crypt",
"rounds_number": 70000,
"update_scheme": true,
...
修改(实测 PUT 200 → 回读确认 → 复原):
$ curl -s -o /dev/null -w 'update PUT: %{http_code}\n' -H "$AUTH" -H 'Content-Type: application/json' \
-X PUT "$BASE/api/v2/parameters/global/core/" -d '{"items_per_page": 50}'
update PUT: 200
全部参数组清单与逐项含义见同专栏《Modoboa 2.11.1 配置参数详解》第四至五章。
五、典型场景实战(一条龙)
场景:给新客户开通"域名 + 管理员账号 + 邮箱 + postmaster 别名"。按顺序调用(本节四条命令均已实测,创建回显 201):
BASE=http://127.0.0.1
H='-H Host:mail.example.com -H Authorization:Token<你的TOKEN> -H Content-Type:application/json'
# 1. 建域名(实测 201)
curl -s $H -X POST "$BASE/api/v2/domains/" -d '{"name":"client.cn","type":"domain","enabled":true}'
# 2. 建域管理员(DomainAdmins)并绑定邮箱与管辖域(实测 201)
curl -s $H -X POST "$BASE/api/v2/accounts/" \
-d '{"username":"ops@client.cn","password":"Strong!Pass1","role":"DomainAdmins","mailbox":{"use_domain_quota":true},"domains":["client.cn"]}'
# {"pk":3,"username":"ops@client.cn",...,"mailbox":{"pk":2,"use_domain_quota":true,...},"role":"DomainAdmins",...}
# 3. 建 postmaster 别名指向该邮箱(实测 201)
curl -s $H -X POST "$BASE/api/v2/aliases/" \
-d '{"address":"postmaster@client.cn","recipients":["ops@client.cn"],"enabled":true}'
# 4. 核对(实测回显节选)
curl -s $H "$BASE/api/v2/identities/?search=client.cn"
# [{"pk":3,"type":"account","identity":"ops@client.cn",...,"tags":[{"name":"account",...},{"name":"DomainAdmins","label":"DomainAdmins","type":"grp"}],"enabled":true,...},
# {"pk":5,"type":"alias","identity":"postmaster@client.cn","name_or_rcpt":"ops@client.cn","tags":[{"name":"alias","label":"alias","type":"idt"}],"enabled":true,...}, ...]
第 2 步的 domains 数组把域管理员管辖域绑定为该账号权限(实测生效:ops@client.cn 以 DomainAdmins 角色入库);第 4 步回显中别名 postmaster@client.cn 的收件人已指向 ops@client.cn(name_or_rcpt 字段)。该场景亦可用官方 Web 面板逐步操作,API 版适合批量/CI 自动化。
六、限流与错误处理(全实测)
6.1 限流规则
settings.py(2.11.1 实测文件):
'DEFAULT_THROTTLE_RATES': {
'user': '300/minute',
'ddos': '5/second',
'ddos_lesser': '200/minute',
'login': '10/minute',
'password_recovery_request': '12/hour',
'password_recovery_totp_check': '25/hour',
'password_recovery_apply': '25/hour'
},
作用范围(实测 + 源码 modoboa/lib/throttle.py 确认):
user(300/分钟):全局默认,每个认证用户;ddos_lesser(200/分钟):GET 类动作(list/retrieve/dns_detail 等),按"用户 × 视图"计;ddos(5/秒):POST/PATCH/DELETE 等写动作,按"用户 × 视图"计;login(10/分钟):登录端点(计数成功后自动重置);- 其余为口令找回流程的专项限流。
6.2 实测触发 429
对同一端点(POST /api/v2/domains/)无间隔连发 8 次(均带合法 Token,body 为空故前 5 次为校验 400):
400 400 400 400 400 429 429 429
$ # 第 6 次起被限流:
{"detail":"Request was throttled. Expected available in 1 second."}
status: 429
集成侧应按 Retry-After/指数退避处理 429;批量脚本建议对写操作加 200ms 以上间隔(实测 0.3s 间隔连发 8 次未触发)。
6.3 错误码速查(本篇实测汇总)
| 状态码 | 触发场景 | 实测响应体 |
|---|---|---|
| 400 | 请求体校验失败 | {"password":["This field is required."]} |
| 401 | 未携带凭据 | {"detail":"Authentication credentials were not provided."} |
| 403 | 权限不足(如域管理员调超管端点) | {"detail":"You do not have permission to perform this action."} |
| 404 | 引用不存在的本地收件人等 | {"error": "Local recipient admin@example.com not found"} |
| 429 | 写操作超过 5 次/秒/视图 | {"detail":"Request was throttled. Expected available in 1 second."} |
(403 响应体为 DRF 标准文案;其余四行均为本篇逐字实测。)
七、常见问题(FAQ)
Q1:Token 丢失/泄露怎么办?
超管可重置:面板 Settings → API 页,或 POST /api/v2/account/api_token/(重置即旧 Token 失效);命令行可删库重建——python manage.py drf_create_token admin 会重新生成并覆盖旧值。
Q2:curl 请求返回 400 Bad Request 且响应体为空?
大概率是请求 Host 不在 ALLOWED_HOSTS(Django 层拒绝),本篇所有示例都带 -H 'Host: mail.example.com';本地验证时也可 python manage.py runserver 后用 localhost 直连。
Q3:v1 与 v2 该用哪个? 新集成一律 v2(有 OpenAPI 文档与 swagger 调试);v1 仅为兼容保留(本篇实测 v1 域名端点仍 200),官方后续会逐步收敛。
Q4:如何看"还有哪些端点可用"?
浏览器打开 /api/schema-v2/swagger/(实测 200),或 curl /api/schema-v2/ 拿全量 JSON(实测 157 个路径);schema 与代码同步生成,不会滞后。
Q5:能直接用 API 发邮件吗? 不能。Modoboa API 管的是"管理局"(域名/账号/别名/参数/日志),收发信由 Postfix/Dovecot 承担;程序化发信请对接 SMTP(587/25)或邮件网关。
八、参考链接
- 官方 REST API 文档(认证与 Token 说明):https://modoboa.readthedocs.io/en/latest/rest_api.html
- 在线示例 Swagger(官方 Demo):https://demo.modoboa.org/api/schema-v2/swagger/
- Modoboa 主仓库(API 实现
modoboa/*/api/):https://github.com/modoboa/modoboa - 站内同专栏:《Ubuntu 22.04 安装 Modoboa 指南》、《Modoboa 2.11.1 配置参数详解》、《Modoboa 2.11.1 介绍与选型指南》