Mailu 2024.06.65 常用 CLI 命令详解
Mailu 官方管理命令行 flask mailu 逐命令详解:admin/user/domain/alias/password/user-delete/user-import 与 config-export/config-import/config-update 增删改查实测回显,setlimits/setmanager 等未文档化命令,以及 CLI 与 Web 管理台、RESTful API 的分工建议。
Mailu 2024.06.65 常用 CLI 命令详解
目标:详解 Mailu 官方管理命令行(
flask mailu系列命令)的账号/域/别名管理、配置导出导入、域级策略设置等用法,全部命令与回显来自 2024.06.65 实际部署的逐行实测;同时给出官方 CLI 与 Web 管理台、RESTful API 三条管理通道的分工建议。部署过程见《Mailu Docker Compose 部署指南》,配置参数见《Mailu 2024.06.65 配置参数详解》。
一、环境信息
- Mailu:2024.06.65(2024.06 稳定分支锁定版)
- 操作系统:Ubuntu 22.04(x86_64)
- 实测环境:本专栏部署指南篇搭建的
mail.example.com(主域example.com,另有实测副域example.net),管理员admin@example.com - CLI 依据:官方管理命令行文档
https://mailu.io/2024.06/cli.html(查询日期 2026-10-21)+ 实际部署验证
二、CLI 概览
Mailu 官方以多服务协作栈发行(见《Mailu 2024.06.65 介绍与选型指南》第三章),管理命令行内置于其中的 admin 服务(Flask 应用自带 CLI),因此官方调用方式是进入 admin 服务执行 flask mailu <命令>:
docker compose exec admin flask mailu <子命令> [参数]
(后续命令均在部署目录 /opt/data/quzuo/tmp/mailu/compose/ 下执行;交互式终端可省略 -T,脚本/管道场景必须加 -T。)
顶层帮助(flask mailu --help)实测回显:
Usage: flask mailu [OPTIONS] COMMAND [ARGS]...
Mailu command line
Options:
-e, --env-file FILE Load environment variables from this file. python-
dotenv must be installed.
-A, --app IMPORT The Flask application or factory function to load, in
the form 'module:name'. Module can be a dotted import
or file path. Name is not required if it is 'app',
'application', 'create_app', or 'make_app', and can be
'name(args)' to pass arguments.
--debug / --no-debug Set debug mode.
--version Show the Flask version.
-h, -?, --help Show this message and exit.
Commands:
admin Create an admin user
advertise Advertise this server against statistic services.
alias Create an alias
alias-delete delete alias
config-export Export configuration as YAML or JSON to stdout or file
config-import Import configuration as YAML or JSON from stdin or file
config-update Sync configuration with data from YAML (deprecated)
db Perform database migrations.
domain Create a domain
mailu Mailu command line
password Change the password of an user
routes Show the routes for the app.
run Run a development server.
setlimits Set domain limits
setmanager Make a user manager of a domain
shell Run a shell in the app context.
user Create a user
user-delete disable or delete user
user-import Import a user along with password hash
命令全景(★=官方 cli.html 文档收录;☆=官方文档未收录但实测存在):
| 命令 | 用途 | 关键参数 |
|---|---|---|
★ admin | 创建全局管理员(连带自动建域) | localpart domain password + --mode |
★ user | 创建用户 | localpart domain password 及可选属性 |
★ domain | 创建域 | domain_name |
★ password | 改用户口令 | user domain password |
★ alias / alias-delete | 建/删别名 | 目标地址列表逗号分隔 |
★ user-delete | 停用/删除用户 | email + -r/--really |
★ user-import | 按口令哈希导入用户(迁移场景) | localpart domain hash scheme |
★ config-export | 导出全部配置为 YAML/JSON | --full --secrets --dns --json -o |
★ config-import | 从 YAML/JSON 导入配置 | --update --dry-run --verbose |
★ config-update | YAML 增量同步(已标记 deprecated) | --delete-objects |
☆ setlimits | 设置域级限制(邮箱数/别名数/配额) | domain_name max_users max_aliases max_quota_bytes |
☆ setmanager | 把用户设为域管理员 | user domain |
☆ advertise | 向统计服务声明本服务器 | 无参数 |
☆ shell | 进入应用上下文 shell | — |
☆ db | 数据库迁移 | Flask-Migrate 子命令 |
☆ routes / run / mailu | Flask 自带:路由表/开发服务器/CLI 入口别名 | — |
💡 说明:
user-import与user的核心区别——前者把传入值当作已存在的口令哈希直接写入(迁移其他邮件系统时有用),后者把传入值当作明文口令现场哈希。setlimits/setmanager虽未见于官方 cli.html,但实测存在且可用,管理多域时可作 Web 界面的命令行替代。
三、账号与域管理命令
3.1 创建域:domain
$ docker compose exec -T admin flask mailu domain example.net
成功时静默无输出。创建全局管理员时也会连带建域(见 3.2)。
3.2 创建全局管理员:admin
$ docker compose exec -T admin flask mailu admin <localpart> <domain> <password> --mode <mode>
--mode 取值 create(默认,已存在报错)/ifmissing(存在则跳过)/update(存在则更新口令)——与 mailu.env 的 INITIAL_ADMIN_MODE 同一套语义。本专栏部署即由 INITIAL_ADMIN_* 变量在首启时执行了等价命令,admin 日志留痕:INFO:root:Creating initial admin account admin@example.com with mode ifmissing。
3.3 创建用户:user
$ docker compose exec -T admin flask mailu user user1 example.com 'q1w2e3r4'
成功时静默。可用属性与 config-update 的 user 段一致(comment、quota_bytes、global_admin、enable_imap、enable_pop、forward_enabled、forward_destination、reply_enabled、displayed_name、spam_enabled、spam_threshold 等)。
3.4 修改口令:password
$ docker compose exec -T admin flask mailu password user2 example.net 'q1w2e3r4'
同样静默成功。口令立即生效,不影响该用户已登录的会话。
3.5 停用/删除用户:user-delete
$ docker compose exec -T admin flask mailu user-delete user2@example.net
注意语义:官方文档明确"名为 delete,默认只做停用"——因为 Mailu 不会连带清理用户数据(邮件与 Webmail 联系人),加 -r/--really 才真删(且建议先手工清理用户数据)。停用效果实测:
$ docker compose exec -T admin flask mailu config-export user.email user.enabled
user:
- email: admin@example.com
enabled: true
- email: user1@example.com
enabled: true
- email: user2@example.net
enabled: false
3.6 按哈希导入用户:user-import
迁移场景(只拿得到旧系统口令哈希):
$ docker compose run --rm admin flask mailu user-import myuser example.net \
'$6$51ebe0cb9f1dab48effa2a0ad8660cb489b445936b9ffd812a0b8f46bca66dd549fea530ce' \
'SHA512-CRYPT'
注意官方示例用的是 docker compose run --rm(一次性执行),与 exec 的区别是 run 会新起一个临时实例执行后销毁。哈希方案名要与旧系统一致(SHA512-CRYPT/MD5-CRYPT 等)。
四、别名管理命令
# 创建别名 support@example.net -> user1@example.com(多目的地用逗号分隔)
$ docker compose exec -T admin flask mailu alias support example.net "user1@example.com"
# 删除别名
$ docker compose exec -T admin flask mailu alias-delete support@example.net
两命令成功时均静默。别名支持通配(--wildcard)。删除后可用 config-export 复核:
$ docker compose exec -T admin flask mailu config-export alias.email alias.destination
alias: []
五、配置导出与导入
5.1 导出:config-export
帮助(实测):
Usage: flask mailu config-export [OPTIONS] [FILTER]...
Export configuration as YAML or JSON to stdout or file
Options:
-f, --full Include attributes with default value.
-s, --secrets Include secret attributes (dkim-key, passwords).
-d, --dns Include dns records.
-c, --color Force colorized output.
-o, --output-file FILENAME Save configuration to file.
-j, --json Export configuration in json format.
-?, -h, --help Show this message and exit.
行为规则:默认只导出非默认值属性;要全量加 --full;要含明文秘密(DKIM 私钥、口令)加 --secrets;要含 DNS 记录(MX/SPF/DKIM/DMARC)加 --dns;可用过滤器只导指定对象或属性(如 user、domain.name,过滤器点名了的属性自动包含)。实测样例:
$ docker compose exec -T admin flask mailu config-export user.email user.global_admin
user:
- email: admin@example.com
global_admin: true
- email: user1@example.com
global_admin: false
$ docker compose exec -T admin flask mailu config-export alias.email alias.destination
alias:
- email: info@example.net
destination:
- user1@example.com
备份建议:-o 落文件 + --dns,配合 --secrets 才是可恢复的完整备份(秘密默认脱敏)。
5.2 导入:config-import
帮助(实测):
Usage: flask mailu config-import [OPTIONS] [FILENAME|-]
Import configuration as YAML or JSON from stdin or file
Options:
-v, --verbose Increase verbosity.
-s, --secrets Show secret attributes in messages.
-q, --quiet Quiet mode - only show errors.
-c, --color Force colorized output.
-u, --update Update mode - merge input with existing config.
-n, --dry-run Perform a trial run with no changes made.
-?, -h, --help Show this message and exit.
要点:
- 不带
--update默认整库替换(现有配置先清空再导入),只想合并增量必须加--update; - stdin 传入必须用
-T(flask mailu config-import -u -); - 删单条/清空的特殊记法:
- -name:example.com(删指定数组对象)、- -user1@example.com(删指定列表项)、- -key:null(删全部剩余/重置默认值)、- -prune-(清空全部剩余列表项); - 新建域时可用魔法值
dkim_key: -generate-让系统现生成 DKIM 密钥。
干跑实测(只演练不落库):
$ printf 'user:\n - email: user4@example.net\n password: q1w2e3r4\n' | \
docker compose exec -T admin flask mailu config-import -nv -
Dry run. Not committing changes.
Created: user(1)
实际导入实测(增量合并,导入一个别名):
$ printf 'alias:\n - email: postmaster@example.net\n destination:\n - user1@example.com\n' | \
docker compose exec -T admin flask mailu config-import -u -
Committing changes.
Created: alias(1)
5.3 增量同步:config-update(deprecated)
官方已将其标记为 deprecated(新场景用 config-import),存量脚本迁移提示:两者口令字段约定不同——
config-update的 user 段要password_hash(哈希):直接传明文$ HASH=$(openssl passwd -6 q1w2e3r4) $ printf 'users:\n - localpart: user3\n domain: example.net\n password_hash: %s\n' "$HASH" | \ docker compose exec -T admin flask mailu config-update Created: user(1), alias(1)password会撞数据库非空约束(实测报错IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: user.password);config-import的 user 段要password(明文)。
5.4 批量 YAML 模板
config-update 的输入格式(官方 cli.html 原样):
users:
- localpart: foo
domain: example.com
password_hash: klkjhumnzxcjkajahsdqweqqwr
aliases:
- localpart: alias1
domain: example.com
destination: "user1@example.com,user2@example.com"
不指定 --delete-objects 时只增改、不删缺失条目;指定后以 YAML 为准做全量对齐。
六、域策略与未文档化命令
6.1 设置域级限制:setlimits
Usage: flask mailu setlimits [OPTIONS] DOMAIN_NAME MAX_USERS MAX_ALIASES MAX_QUOTA_BYTES
用于多租户托管:限制每个域可建邮箱数/别名数/总配额(字节);-1 表示不限。等效于管理台域名编辑页的三个限制字段。
6.2 任命域管理员:setmanager
$ docker compose exec -T admin flask mailu setmanager <user邮箱> <domain>
把普通用户提升为指定域的管理员(只能管理该域的账号),等效于管理台的"域管理员"指派。撤销同理走 Web 界面。
6.3 其他内置命令
shell:进入应用上下文的 Python shell(调试数据层用);db:数据库迁移(Flask-Migrate 包装,db status/db upgrade);advertise:向统计聚合服务上报本服务器存在(DISABLE_STATISTICS=true后无实际动作);routes/run:Flask 框架自带(开发调试用,生产无关)。
七、CLI 与 Web 管理台、REST API 的分工
Mailu 三条管理通道操作同一份数据,能力对等关系(官方 api.html 原话:"Anything that can be configured via the Mailu web administration interface, can also be configured via the API"):
| 通道 | 适用场景 | 认证 |
|---|---|---|
flask mailu CLI | 批量脚本、迁移、无图形环境、CI 里初始化 | 服务器本地执行 |
| Web 管理台 | 日常运营、一次性操作、域管理员分权 | 登录会话 |
| RESTful API | 与外部系统对接、自动化巡检 | API_TOKEN Bearer |
API 速览(实测于本部署,WEB_API=/api,Swagger UI 见 https://<主机>/api/,机读定义 /api/v1/swagger.json 共 18 组端点:alias/alternative/domain(+dkim/manager/users)/relay/token/tokenuser/user 等):
$ curl -sk -H 'Authorization: q1w2e3r4' -X POST \
-H 'Content-Type: application/json' \
-d '{"name":"example.org","max_users":-1,"max_aliases":-1,"max_quota_bytes":0,"signup_enabled":false}' \
https://127.0.0.1:8132/api/v1/domain
{"message":"Domain example.org has been created"}
选型建议:人值守的操作走 Web 台;脚本化/批量走 CLI;跨系统集成走 API。CLI 与 API 的一个差异点要记住:CLI 建域不生成 DKIM 密钥(flask mailu domain/admin 均如此),Web 台建域会生成;CLI 用户可用 API 补:POST /api/v1/domain/<域名>/dkim 生成 DKIM 密钥。
八、常见问题
Q1:命令成功为什么不打印任何东西? 官方 CLI 风格:user/domain/alias/password 等成功时静默,失败时抛栈回显。核验请用 config-export(脚本中可用退出码判断)。
Q2:config-update 报 NOT NULL constraint failed: user.password? config-update 只认 password_hash 字段(预哈希);明文口令请用 flask mailu user,或改用 config-import(它要 password 字段)。详见 5.3 节。
Q3:flask mailu --help 末尾冒出一段 AssertionError 栈? 实测在 --help 正常输出后,进程退出阶段会打印 AssertionError: There is no current event loop in thread 'MainThread'. 的栈——Flask CLI 退出钩子的已知怪象,不影响帮助内容正确性,脚本判断请以退出码/正文为准。
Q4:命令行建的域没有 DKIM? 见第七章末尾说明:用管理台"重新生成密钥"或 API POST /api/v1/domain/<域名>/dkim。
Q5:脚本里批量执行要注意什么? ① docker compose exec 必须加 -T(非 TTY 场景);② 认证限速对 CLI 不生效(本地操作),但导入大量用户后建议同步设置 setlimits 收紧域级配额;③ config-import 不带 --update 会整库替换,务必先 --dry-run 演练。
九、参考链接
- Mailu 命令行官方文档:https://mailu.io/2024.06/cli.html
- Mailu RESTful API 官方文档:https://mailu.io/2024.06/api.html
- 官方配置参考:https://mailu.io/2024.06/configuration.html
- 本站相关文章:《Mailu Docker Compose 部署指南》《Mailu 2024.06.65 配置参数详解》《Mailu 2024.06.65 介绍与选型指南》