docker-mailserver 账户管理实战:基于 `setup` CLI 与文件型配置的 Provisioner(File)完整指南
2026/9/20 15:48:15 网站建设 项目流程
  • 后端
  • 通信
  • 云原生

【免费下载链接】docker-mailserver

Production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) running inside a container.

项目地址:https://gitcode.com/gh_mirrors/do/docker-mailserver
点击查看免费下载

本文围绕 docker-mailserver(DMS)的文件型账户供给器(Provisioner: FILE)展开,系统讲解如何通过容器内的setupCLI 与 Config Volume 中的三个核心配置文件(postfix-accounts.cfpostfix-virtual.cfdovecot-quotas.cf)管理邮箱账户、别名与配额,并深入解析其底层实现(脚本、Postfix/Dovecot 配置生成与测试用例)。读完本文,你将掌握 DMS 账户体系的完整操作链路、配置文件格式与已知边界,能够独立完成从建号、设别名、配配额到排障的整套实战任务。


1. 总览:DMS 的两种账户供给方式与 File 模式定位

DMS 通过环境变量ACCOUNT_PROVISIONER选择账户来源:

  • FILE(默认):账户、别名、配额存储在 Config Volume 的纯文本配置文件中,由容器启动脚本转换成 Postfix 与 Dovecot 可用的内部配置;
  • LDAP:账户信息来自 LDAP 目录(参见 LDAP Provisioner 文档)。

本文只讨论 File 模式。在mailserver.envACCOUNT_PROVISIONER默认留空,由 target/scripts/helpers/accounts.sh 中的_create_accounts()判断:仅当该值等于FILE时才走文件型账户创建流程(见 accounts.sh),因此“不设置”即等价于 File 模式。

File 模式下,所有配置都归属于Config Volume(默认映射docker-data/dms/config/→ 容器内/tmp/docker-mailserver/),具体挂载方式可参考 Optional Config 文档的 Volumes 章节。

2. 管理方式:setupCLI

官方推荐通过容器内的setupCLI 管理账户及其关联配置文件。它是一系列 Bash 脚本的入口,在 target/bin/setup 中定义了全部子命令的分发逻辑:

setup [ OPTIONS... ] COMMAND [ help | ARGUMENTS... ] COMMAND := { email | alias | quota | dovecot-master | config | relay | debug } SUBCOMMAND
  • setup email add/update/del/list/restrict
  • setup alias add/del/list
  • setup quota set/del
  • setup dovecot-master add/update/del/list
  • setup config dkim
  • setup relay add-auth/add-domain/exclude-domain
  • setup fail2bansetup debug ...

完整命令列表可用setup help查看;每个子命令都支持help参数获取用法说明(例如setup email add help)。

2.1 进入容器执行

文档示例先启动一个基础实例,再进入容器执行setup

# 启动一个基础 DMS 实例,然后进入容器使用 setup CLI: docker run --rm -itd --name dms --hostname mail.example.com mailserver/docker-mailserver docker exec -it dms bash # 创建账户: setup email add hello@example.com your-password-here # 创建别名: setup alias add your-alias-here@example.com hello@example.com # 将邮箱容量限制为 10 MiB: setup quota set hello@example.com 10M

2.2 宿主机侧的setup.sh包装器

仓库根目录提供了 setup.sh,它自动探测 Docker/Podman(见 setup.sh),找到运行中的 DMS 容器后,等价于执行docker exec -it <container> setup <args>(见 setup.sh);若没有运行中的容器,则会基于镜像临时起一个新容器执行命令。也就是说,上面的命令在宿主机上同样可以写成:

./setup.sh email add hello@example.com your-password-here ./setup.sh alias add your-alias-here@example.com hello@example.com ./setup.sh quota set hello@example.com 10M

2.3 安全密码输入

命令行不带密码时,脚本会交互式提示输入(见 postfix-accounts.sh 的_password_request_if_missing():两次静默输入并做一致性校验),从而避免密码进入 shell 历史记录:

$ setup email add hello@example.com Enter Password: Confirm Password:

2.4 删除账户的级联行为

setup email del会同时删除该账户关联的别名与配额。从源码 delmailuser 可以看到执行顺序:

  1. 校验账户存在;
  2. 可选删除磁盘上的邮箱目录(-y确认删除 /-n明确保留,见 delmailuser 的交互提示与-y强制);
  3. 删除该账户名下的全部虚拟别名(_manage_virtual_aliases_delete '_');
  4. 删除其配额条目(_manage_dovecot_quota_delete);
  5. 最后才从postfix-accounts.cf删除账户。

测试用例同样验证了这一级联行为与“缺少配置文件时不报错”的容错逻辑(见 account_management.bats)。

3. 配置参考:账户(Accounts)

3.1 文件位置与格式

配置文件docker-data/dms/config/postfix-accounts.cf

格式为逐行文本,两列字段以|分隔:

  • User(用户):账户邮箱主地址;
  • Password(密码):账户密码的 SHA512-CRYPT 哈希(下方示例中明文密码为secret)。

示例(假设 DMS 为example.com域管理邮件):

hello@example.com|{SHA512-CRYPT}$6$W4rxRQwI6HNMt9n3$riCi5/OqUxnU8eZsOlZwoCnrNgu1gBGPkJc.ER.LhJCu7sOg9i1kBrRIistlBIp938GdBgMlYuoXYUU5A4Qiv0

不用setup email add生成密码哈希:兼容的哈希可由 Dovecot 工具直接生成:

doveadm pw -s SHA512-CRYPT -u hello@example.com -p secret

这实际上就是setup email add在底层所做的操作:_manage_accounts()调用doveadm pw -s SHA512-CRYPT -u "${MAIL_ACCOUNT}" -p "${PASSWD}"生成哈希后写入文件(见 postfix-accounts.sh)。

3.2 底层消费:Postfix vmailbox 与 Dovecot UserDB

setup email add只把条目写入postfix-accounts.cf,真正的“建号”发生在变更检测(changedetector)触发后。由 accounts.sh 的_create_accounts()完成:

  • 逐行以|为分隔符解析(while IFS=$'|' read -r LOGIN PASS USER_ATTRIBUTES),忽略注释与空行;
  • 为每个账户生成/etc/postfix/vmailboxLOGIN DOMAIN/USER/(Postfix 的virtual_mailbox_maps);
  • 为每个账户生成/etc/dovecot/userdb行,格式为user:password:uid:gid:(gecos):home:(shell):extra_fields,其中 uid/gid 使用DMS_VMAIL_UID/DMS_VMAIL_GID,home 为/var/mail/<domain>/<user>/home
  • 创建邮箱目录/var/mail/<domain>/<user>/home,若存在docker-data/dms/config/<login>.dovecot.sieve则复制为用户的.dovecot.sieve筛件;
  • 账户的本地部分(local-part)与域部分(domain-part)会用于填充 Postfix 的 vhost 域表(见 postfix.sh)。

容器启动脚本 dovecot.sh 会在检测到postfix-accounts.cf后启用auth-passwdfile.inc(passdb),实现 IMAP/POP3 的密码文件认证。

3.3 重要约定

  • 大小写归一化:创建账户时会自动将邮箱地址规范为小写——DMS 不支持同一地址的多种大小写变体。源码在 postfix-accounts.sh 的_arg_check_mail_account()中实现:检测到大写字母时发出警告并转小写。测试用例专门验证了USeRx@domain.tld被归一化为userx@domain.tld(见 account_management.bats)。另外,登录认证对大小写不敏感(测试中USER1@...大写登录可成功,见同文件 L62-L66)。
  • 登录用户名即邮箱地址:所选邮箱地址同时是邮件客户端认证时的登录用户名。
  • 邮箱目录结构:账户邮箱位于/var/mail/<domain>/<local-part>,测试中通过[[ -d /var/mail/localhost.localdomain/user1 ]]验证(见 account_management.bats)。

3.4 Dovecot "extra fields" 扩展列

postfix-accounts.cf中追加第三列可自定义“额外字段”(extra fields),用于在转换为 Dovecot UserDB 条目时携带额外属性(如自定义 quota 属性userdb_quota_storage_sizeuserdb_quota_storage_grace,参见 accounts.sh 的_add_attribute_dovecot_quota())。

注意:DMS 本身并不理解这些自定义内容,只是原样透传。若这些字段改变了脚本所依赖的约定(如 mailbox 路径或类型),可能导致预期之外的 bug。

4. 配置参考:别名(Aliases)

4.1 文件位置与格式

配置文件docker-data/dms/config/postfix-virtual.cf

格式为逐行“键值对”(别名目标地址),以空白字符分隔。

示例(假设 DMS 为example.com域管理邮件):

# 别名投递到已有账户: alias1@example.com hello@example.com # 别名转发到外部邮箱: alias2@example.com external-account@gmail.com

从源码看,别名键(第一列)可以是user@domain、只有本地部分的user,以及通配的@domain(见 postfix-virtual.sh)。

4.2 底层消费

容器启动时,aliases.sh 的_handle_postfix_virtual_config()postfix-virtual.cf直接复制为/etc/postfix/virtual;Postfix 的virtual_alias_maps默认配置为texthash:/etc/postfix/virtual(见 target/postfix/main.cf)。

值得注意的联动逻辑:当ENABLE_QUOTAS=1时,accounts.sh 的_create_dovecot_alias_dummy_accounts()会为“指向本地真实账户”的别名在 Dovecot userdb 中生成共享同一存储的“dummy 条目”,供quota-status策略服务在入站投递时做配额检查,以降低退信(backscatter)风险。该行为由测试显式验证(见 account_management.bats)。

4.3 已知问题与限制

setupCLI 禁止别名与账户共用同一地址:目前无法用setup email addsetup alias add添加一个已作为别名或账户存在的地址。该限制源于历史 bug(账户/别名重叠曾引发投递问题),但仍存在合法的重叠使用场景。作为临时方案,你可以手动编辑postfix-virtual.cf绕过此限制——除setupCLI 外,运行时没有针对这一限制的其他检查(对应校验逻辑在 postfix-virtual.sh 与 postfix-accounts.sh 中)。

通配 catch-all(@example.com

  • 这种无本地部分的别名受支持,但必须牢记:Postfix 中别名的优先级高于账户的真实地址
  • 因此通配会先被匹配,把整个域的信件都导向别名目标;对域内每个非别名地址,你需要额外为其配置一个别名来兜底;
  • Postfix 读取别名配置时会选择与收件人地址最匹配的条目,因此更具体的别名必须声明在通配别名之前

别名链与多收件人:虽然技术上可以向多个收件人投递,但 DMS 并不官方支持:

  • 某些功能集成(如配额 dummy 账户、setup alias add的增删逻辑)假定每个别名只有一个目标,多目标可能出问题;
  • 嵌套别名(目标本身又是别名)同样不受支持,例如与setup alias add存在兼容性问题。Postfix 本身虽可递归解析别名,但项目脚本/功能对此支持有限(见 postfix-virtual.sh 的警告注释)。

4.4 配置 RegEx 别名

配置文件docker-data/dms/config/postfix-regexp.cf

该文件与postfix-virtual.cf类似,区别在于别名值改为正则模式匹配。此功能没有setupCLI 支持,只能手动改配置文件。

示例:将test用户的所有邮件投递到qa@example.com

# 记得转义正则特殊字符,如 `.` => `\.`, # 否则你的别名模式可能比预期更宽松: /^test[0-9][0-9]*@example\.com/ qa@example.com

4.5 技术细节:优先级与加载机制

  • postfix-virtual.cf拥有更高优先级,postfix-regexp.cf仅在虚拟别名表中未找到匹配时才被检查;
  • 两者都会被复制到容器内/etc/postfix/(分别是/etc/postfix/virtual/etc/postfix/regexp),并在main.cfvirtual_alias_maps中配置。因为postfix-virtual.cf在该设置中声明在前(见 target/postfix/main.cf),它会先被处理,postfix-regexp.cf作为后备(_handle_postfix_regexp_config()通过_add_to_or_update_postfix_main追加pcre:/etc/postfix/regexp,见 aliases.sh)。

5. 配置参考:配额(Quotas)

5.1 文件位置与格式

配置文件docker-data/dms/config/dovecot-quotas.cf

格式为逐行文本,两列字段以:分隔:

  • Dovecot UserDB 账户:DMS 账户,应能在postfix-accounts.cf中找到对应条目;
  • 配额上限:以字节表示(支持二进制单位后缀:M=>MiBG=>GiB)。

示例:为账户hello@example.com设置不超过 5 GiB 的存储上限:

hello@example.com:5G

5.2 底层消费

启动时_add_attribute_dovecot_quota()从该文件读取配额,按:切分后转换为 Dovecot userdb 的userdb_quota_storage_size额外字段,并根据单位后缀额外追加userdb_quota_storage_grace(取数值的 1/10 作为宽限空间,见 accounts.sh)。写操作由 dovecot-quotas.sh 的_manage_dovecot_quota()完成(setup quota set对应updatesetup quota del对应delete)。

默认ENABLE_QUOTAS=1(见 mailserver.env)。测试验证了setup email list在配额启用/禁用时输出格式的差异(见 account_management.bats)。

6. 其他相关能力

  • Dovecot Master 账户setup dovecot-master add/update/del/list管理docker-data/dms/config/dovecot-masters.cf,复用与账户相同的管理逻辑(见 postfix-accounts.sh),用于支持管理员的“主账户”登录场景。完整机制可参考 Master Accounts 文档。
  • 账户列表查询setup email list(底层为 listmailuser)列出全部账户。
  • 变更检测:所有setup写操作完成后,由容器的 changedetector 服务感知文件变化并重新生成 Postfix/Dovecot 内部配置(见 addmailuser 的注释),因此账户不会“即时”生效,存在短暂延迟,属正常现象。

7. 从setupCLI 到配置文件的完整调用链

将前述内容串联起来,一次setup email add的完整链路如下:

  1. 宿主机./setup.sh解析出容器/镜像后,执行docker exec ... setup email add ...(setup.sh);
  2. 容器内setup脚本将email add分发给addmailuser(target/bin/setup);
  3. addmailuser调用_manage_accounts_create(addmailuser);
  4. _manage_accounts完成地址校验、大小写归一化、密码哈希生成,并写入/tmp/docker-mailserver/postfix-accounts.cf(postfix-accounts.sh);
  5. changedetector 触发后,_create_accounts()根据配置文件重建/etc/postfix/vmailbox/etc/dovecot/userdb,并创建邮箱目录(accounts.sh)。

对应地,setup alias addaddalias_manage_virtual_aliases_update写入postfix-virtual.cfsetup quota setsetquota_manage_dovecot_quota_update写入dovecot-quotas.cf。所有数据库文件的操作统一收敛在 database/manage 目录下,结构清晰、便于维护。

8. 实操核对清单

需求推荐命令 / 文件底层消费方
添加账户setup email add <addr> [<pass>]postfix-accounts.cf→ vmailbox / Dovecot userdb
删除账户(含别名、配额)setup email del [-y|-n] <addr>级联清理三个配置文件
修改密码setup email update <addr> [<pass>]重写postfix-accounts.cf哈希
添加别名setup alias add <alias> <target>postfix-virtual.cf/etc/postfix/virtual
RegEx 别名手动编辑postfix-regexp.cf/etc/postfix/regexpvirtual_alias_maps后备)
设置配额setup quota set <addr> <size>dovecot-quotas.cf→ userdb 额外字段
查看账户setup email list读取postfix-accounts.cf

9. 进一步阅读

  • 配置文件所属的 Config Volume 说明
  • 账户管理的总览文档:Account Management 概述
  • LDAP 供给方式对照阅读:Provisioner - LDAP
  • user-patches.sh自定义容器内配置:User Patches
  • 相关源码与测试:target/scripts/helpers/accounts.sh、target/scripts/helpers/database/manage/postfix-accounts.sh、target/scripts/helpers/database/manage/postfix-virtual.sh、target/scripts/helpers/database/manage/dovecot-quotas.sh、test/tests/parallel/set3/mta/account_management.bats
  • 后端
  • 通信
  • 云原生

【免费下载链接】docker-mailserver

Production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) running inside a container.

项目地址:https://gitcode.com/gh_mirrors/do/docker-mailserver
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询