Mailman 3.3.10 配置参数详解

Mailman 3.3.10 三份配置文件逐段详解:mailman.conf 生效配置、REST 凭据/归档开关/LMTP 端口/白名单/max_message_size 五组改生效验证闭环实测与生产模板。

Mailman邮件服务器邮件列表2026/10/21

Mailman 3.3.10 配置参数详解

目标:逐段讲透 GNU Mailman 3.3.10 的配置体系——Core 的 /etc/mailman3/mailman.cfg、归档插件的 mailman-hyperkitty.cfg、Web 面的 /etc/mailman3/settings.py,每个关键参数都给出「默认值实测 → 修改 → 生效 → 行为验证」的闭环。已在 Ubuntu 22.04.5 + Mailman 3.3.10 实测通过,安装过程见 《Ubuntu 22.04 安装 Mailman 指南》。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS,主机名 list.example.org;
  • Mailman 3.3.10(Tom Sawyer)+ mailman-web 0.0.9(Postorius 1.3.13 / HyperKitty 1.3.12)+ mailman-hyperkitty 归档插件;
  • 配置文件:/etc/mailman3/mailman.cfg(Core)、/etc/mailman3/mailman-hyperkitty.cfg(归档插件)、/etc/mailman3/settings.py(Web 面);
  • 运行数据:/opt/mailman/var([paths.custom] var_dir);Web 数据 /opt/mailman/web;
  • 服务:Core(systemd mailman3,REST 8001 / LMTP 8024)、Web 面(systemd mailman-web,uWSGI 8000,nginx 80)、postfix 25;
  • REST 凭据:restadmin / q1w2e3r4;演示列表:test@list.example.org,成员 alice@example.org、bob@mbox.example.org。

二、前置条件

  1. 已按 《Ubuntu 22.04 安装 Mailman 指南》 完成安装,systemctl is-active mailman3 mailman-web 均为 active;
  2. 能以 sudo -u mailman 执行 Core 命令行;
  3. 能以 restadmin/q1w2e3r4 访问 http://127.0.0.1:8001/3.1/ REST API(curl)。

三、参数查看与修改方式

3.1 查看:mailman conf 是生效配置的唯一权威来源

mailman conf 打印的是合并后的最终生效配置(含默认值),而不是文件原文。帮助如下(实测):

sudo -u mailman /opt/mailman/venv/bin/mailman conf --help
Usage: mailman conf [OPTIONS]

  Print the Mailman configuration.

Options:
  -o, --output FILENAME  File to send the output to.  If not given, or if '-'
                         is given, standard output is used.
  -s, --section TEXT     Section to use for the lookup.  If no key is given,
                         all the key-value pairs of the given section will be
                         displayed.
  -k, --key TEXT         Key to use for the lookup.  If no section is given,
                         all the key-values pair from any section matching the
                         given key will be displayed.
  -h, --help             Show this message and exit.

实用组合(实测):

sudo -u mailman /opt/mailman/venv/bin/mailman conf -s mta        # 打印 [mta] 全段
sudo -u mailman /opt/mailman/venv/bin/mailman conf -k site_owner  # 跨段找同名键
sudo -u mailman /opt/mailman/venv/bin/mailman conf | grep -E '^\[(mailman)\]'  # 过滤某段

-s mta 的实测输出(节选):

[mta] configuration: /opt/mailman/etc/postfix-mailman.cfg
[mta] incoming: mailman.mta.postfix.LMTP
[mta] lmtp_host: 127.0.0.1
[mta] lmtp_port: 8024
[mta] outgoing: mailman.mta.deliver.deliver
[mta] smtp_host: 127.0.0.1
[mta] smtp_port: 25
[mta] max_recipients: 10

⚠️ 注意:mailman conf 是只读工具,没有「写回」参数。修改一律编辑配置文件 + 重启服务,再用 mailman conf 验证生效。

3.2 三份配置文件的分工与查找顺序

文件归属生效方式
/etc/mailman3/mailman.cfgCore(含 [archiver.hyperkitty] 段)systemctl restart mailman3
/etc/mailman3/mailman-hyperkitty.cfg归档插件(由 mailman.cfg 的 configuration 键指定)systemctl restart mailman3
/etc/mailman3/settings.pyDjango Web 面(Postorius + HyperKitty)systemctl restart mailman-web

Core 的配置查找顺序(源码 mailman/core/initialize.py 实读):

$MAILMAN_CONFIG_FILE → ./mailman.cfg → ./var/etc/mailman.cfg → ~/.mailman.cfg
→ /etc/mailman.cfg → /etc/mailman3/mailman.cfg

两个实测行为(详见安装篇 4.3 节):root 运行需 --run-as-root;所有路径都找不到配置时会在当前目录自动生成默认配置并遮蔽后续查找。规范:配置只放 /etc/mailman3/mailman.cfg 一处。

💡 技术拓展:settings.py 并没有「默认文件」,mailman-web 的约定是 MAILMAN_WEB_CONFIG 环境变量指向一个 Python 模块(默认 /etc/mailman3/settings.py),文件开头 from mailman_web.settings.base import * 与 from mailman_web.settings.mailman import * 继承官方默认值后逐项覆盖。这套「defaults + 覆盖层」的思路与 mailman.cfg 的「内置默认 + 用户文件 push」一致:你只写差异项,其余继承官方默认。

3.3 修改与生效的标准流程

sudo vi /etc/mailman3/mailman.cfg        # 1. 修改
sudo systemctl restart mailman3          # 2. 生效(Core)
sudo -u mailman /opt/mailman/venv/bin/mailman conf -s <段>   # 3. 验证值已变
# 4. 行为级验证(发信/REST/日志),见第五章各闭环实验

Web 面同理:改 settings.py → systemctl restart mailman-web → curl 行为验证。

四、参数总览

以下为本文环境 mailman conf 实测默认值(本文 mailman.cfg 已按安装篇配置,标注「默认」的值为官方内置默认):

[mailman] 站点与消息处理

键实测值说明
site_owneradmin@example.org站点所有者,OWNER 通知收件人
layoutcustom路径布局,对应 [paths.custom]
default_languageen新列表默认语言
sender_headersfrom from_ reply-to sender依序用于判定发件人的头
noreply_addressnoreply自动回复的免回地址名
cache_life7d缓存寿命
pending_request_life3d待审请求(held)默认保存期
moderator_request_life180d审批请求保存期
listname_chars[-_.0-9a-z]合法列表名字符集
check_max_size_on_filtered_messageno内容过滤后再查体积(默认过滤前查)
run_tasks_every1h例行任务周期

[database] 持久层

键实测值说明
classmailman.database.sqlite.SQLiteDatabaseSQLite 引擎类
urlsqlite:////opt/mailman/var/data/mailman.dbSQLAlchemy 连接串
debugnoSQL 调试日志开关

[mta] 收发与 MTA 对接(完整实测见 3.1 节输出)

键实测值说明
incoming / outgoingpostfix.LMTP / deliver.deliver入站 LMTP、出站 SMTP 两条通道
lmtp_host / lmtp_port127.0.0.1 / 8024Core 收信入口,须与 postfix transport 一致
smtp_host / smtp_port127.0.0.1 / 25Core 出站交回 MTA
max_recipients10单封收件人数上限(防爆破投递)
max_autoresponses_per_day10自动回复每日上限
delivery_retry_period5d投递失败重试窗口
smtp_secure_mode / smtp_user / smtp_passsmtp / 空 / 空出站加密与认证(接外部中继时用)
verp_* 系列见 5.3VERP 退信精确归因组

[webservice] REST API

键实测值说明
hostname / port127.0.0.1 / 8001REST 监听,只绑本机
admin_user / admin_passrestadmin / q1w2e3r4REST 基本认证凭据
api_version3.1API 版本
workers2gunicorn worker 数
use_httpsnoREST 是否 TLS(本地通道保持 no)

[paths.custom] 路径布局(var_dir 派生全部子目录)

键实测值
var_dir/opt/mailman/var
etc_dir / log_dir$var_dir/etc / $var_dir/logs
queue_dir$var_dir/queue
data_dir / list_data_dir$var_dir/data / $var_dir/lists
pid_file / lock_file$var_dir/master.pid / $var_dir/locks/master.lck

[archiver.*] 归档

键实测值说明
[archiver.hyperkitty] classmailman_hyperkitty.Archiver独立插件类(非 core 内置)
[archiver.hyperkitty] enableyes归档总开关
[archiver.hyperkitty] configuration/etc/mailman3/mailman-hyperkitty.cfg插件配置(base_url + api_key)
[archiver.mail_archive] / [archiver.mhonarc] enableno其他归档后端默认关

[runner.*] 队列引擎(每队列实例数/睡眠/自启,实测样例)

[runner.archive] instances: 1  sleep_time: 1s  start: yes
[runner.bad]     instances: 1  sleep_time: 1s  start: no   # 伪 runner,默认禁用

五、核心参数分类详解(每项「改 → 生效 → 验证」闭环)

5.1 [webservice] REST 凭据:配错即 401(实测闭环)

REST 凭据是 Core 与 Web 面的唯一管理通道口令。实验:把 mailman.cfg 的 admin_pass 改成 wrongpass 并重启,用旧凭据访问:

curl -s -u restadmin:q1w2e3r4 -w "\nHTTP=%{http_code}\n" http://127.0.0.1:8001/3.1/system/versions
{"title": "401 Unauthorized", "description": "REST API authorization failed"}
HTTP=401

改回 admin_pass: q1w2e3r4 重启后复测:

{"mailman_version": "GNU Mailman 3.3.10 (Tom Sawyer)", "python_version": "3.10.12 (main, Aug 31 2026, 10:18:17) [GCC 11.4.0]", "api_version": "3.1", "self_link": "http://127.0.0.1:8001/3.1/system/versions", "http_etag": "\"7a0313783b989609a9edd7b586965908b518385e\""}
HTTP=200

⚠️ 双端一致性:改 [webservice] admin_pass 后,settings.py 的 MAILMAN_REST_API_PASS 必须同步改,否则 Postorius/HyperKitty 全站报「与 Mailman 通信失败」。生产改法:两端同值、restart 两个服务、curl 验证 200。

5.2 [archiver.hyperkitty] enable:归档总开关(实测闭环)

改为 enable: no → 重启 Core → 发一封信,mailman.log 的 HyperKitty archived 行不增加;改回 yes 再发一封,立即归档:

sudo -u mailman /opt/mailman/venv/bin/mailman conf -k enable -s archiver.hyperkitty

实测计数证据:

关闭归档后 archived 行数: 3 -> 3      # enable: no,发信后行数不变
恢复归档后 archived 行数: 4           # enable: yes,新信立即归档
Oct 21 04:40:45 2026 (7721) HyperKitty archived message <20261021044042.B835E158BE97@list.example.org> to https://list.example.org/archives/list/test@list.example.org/message/4ORUMMRPGDZD7WS2RCXJKZF2RTJ5KLU7/

💡 说明:enable: no 期间消息正常投递(讨论不受影响),只是不进归档——适合「临时停归档」场景。归档打不开多半是另一回事(插件缺装/密钥错 → 消息 SHUNT,见 FAQ)。

5.3 [mta] lmtp_port:端口错位故障复现(实测闭环)

Core LMTP 与 postfix transport 是一对必须严格对齐的端点。实验:把 lmtp_port 改成 8025(postfix transport 仍指 8024),重启后端口确实换了,但入站信全部被 postfix 排队:

ss -ltn | grep -E '802[45]'
LISTEN 0      100        127.0.0.1:8025       0.0.0.0:*

发信后 postfix 日志(/var/log/mail.log):

Oct 21 04:41:02 list postfix/lmtp[7705]: connect to 127.0.0.1[127.0.0.1]:8024: Connection refused
Oct 21 04:41:02 list postfix/lmtp[7705]: 75F5B158BEBE: to=<test@list.example.org>, relay=none, delay=0, delays=0/0/0/0, dsn=4.4.1, status=deferred (connect to 127.0.0.1[127.0.0.1]:8024: Connection refused)

改回 lmtp_port: 8024 重启即恢复(deferred 队列会自动重投)。ss 显示 8024 重新监听:

LISTEN 0      100        127.0.0.1:8024       0.0.0.0:*

[mta] 其余要点:

  • verp_delivery_interval: 0(默认关闭逐封 VERP):改为 1 则每封出站信都用 VERP 变体地址投递(verp_format: ${bounces}+${local}=${domain}),退信可精确归因到单个成员,代价是每封单独投递;
  • max_recipients: 10:LMTP 收信时 RCPT 数超限即走 moderation(防群发注入),命中会出现在 held 请求的 X-Mailman-Rule-Hits: max-recipients 头(规则集见 5.6 实验);
  • smtp_user/smtp_pass/smtp_secure_mode:Core 出站走外部中继(如云厂商 relayhost)时的认证与 STARTTLS 配置。

5.4 [database] 与 [paths.custom]:换库与搬家

SQLite 适合单机小站;换 PostgreSQL 只改两行(以 Debian/Ubuntu 包 postgresql 与 python3-psycopg2 已装为前提):

[database]
class: mailman.database.sqlatabase.PostgreSQLDatabase
url: postgresql://mailman:q1w2e3r4@127.0.0.1/mailman

⚠️ 换库不迁移数据:新库是空库,列表/成员需重建或用 mailman import 迁移;Web 面数据库(HyperKitty 归档)是另一套 Django 配置(settings.py DATABASES),互不相干。

[paths.custom] var_dir 指向哪,队列、日志、数据库、锁就都在其下派生(实测 5.x 派生关系见第四章总览表)。搬家 = 改 var_dir + 迁移目录 + 重启。

5.5 [mailman] 站点参数(site_owner 实测闭环)

把 site_owner 从 admin@example.org 改为 owner@list.example.org:

sudo -u mailman /opt/mailman/venv/bin/mailman conf -k site_owner
[mailman] site_owner: owner@list.example.org

行为的可观察面:待审请求触发时 Core 给 site_owner 发 OWNER 通知(本文 5.6 实验的 OWNER: <...> 日志行对应邮件投递),站点级系统邮件也发往该地址。改回 admin@example.org 同法验证。

5.6 列表级参数:max_message_size 超限即待审(实测闭环)

邮件体积上限不在全局配置里,而是每个列表一个属性(REST 可查改)。实测:默认 40 KB,改成 1 KB 后发一封约 2.3 KB 的信:

curl -s -u restadmin:q1w2e3r4 "http://127.0.0.1:8001/3.1/lists/test.list.example.org/config" \
  | python3 -c 'import sys,json; print("默认 max_message_size:", json.load(sys.stdin)["max_message_size"], "KB")'
curl -s -u restadmin:q1w2e3r4 -X PATCH -d "max_message_size=1" \
  "http://127.0.0.1:8001/3.1/lists/test.list.example.org/config" -o /dev/null -w "PATCH HTTP=%{http_code}\n"
默认 max_message_size: 40 KB
PATCH HTTP=204

发信后消息没有被拒收或丢弃,而是进入待审(held),规则命中直接写在消息头里(REST held 接口实测节选):

X-Mailman-Rule-Hits: max-size
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; news-moderation; no-subject; digests; suspicious-header

同时 mailman.log 出现给站长的通知行、held 接口 total_size 变 1:

Oct 21 04:44:30 2026 (7798) OWNER: <179255786875.7798.13827231093267562989@list.example.org>

处置与恢复(实测):

curl -s -u restadmin:q1w2e3r4 -X POST -d "action=discard" \
  "http://127.0.0.1:8001/3.1/lists/test.list.example.org/held/1" -o /dev/null -w "POST HTTP=%{http_code}\n"
curl -s -u restadmin:q1w2e3r4 "http://127.0.0.1:8001/3.1/lists/test.list.example.org/held" \
  | python3 -c 'import sys,json; print("剩余 held:", json.load(sys.stdin)["total_size"])'
POST discard HTTP=204
剩余 held: 0

💡 说明:X-Mailman-Rule-Hits/Misses 这一对头是排查「信为什么没过」的金钥匙——15 条 moderation 规则命中哪条一目了然(max-size/max-recipients/member-moderation/dmarc-mitigation 等)。处置动作是 POST action=approve|discard|reject|defer,DELETE 不适用。

5.7 Web 面 settings.py:ALLOWED_HOSTS 白名单(实测闭环)

把 list.example.org 从 ALLOWED_HOSTS 移除并重启 mailman-web,带该 Host 头访问:

curl -s -o /dev/null -w "HTTP=%{http_code}\n" -H "Host: list.example.org" http://127.0.0.1/postorius/lists/
HTTP=400

恢复白名单后复测:

HTTP=200

Django 对白名单外 Host 一律 400(DisallowedHost)。其余 Web 面关键参数的联动关系(凭据/密钥对齐)在 5.1 与 5.2 节已闭环验证:MAILMAN_REST_API_PASS ↔ mailman.cfg admin_pass;MAILMAN_ARCHIVER_KEY ↔ mailman-hyperkitty.cfg api_key;ACCOUNT_DEFAULT_HTTP_PROTOCOL 未配 HTTPS 前必须 http。

六、生产配置模板

小站模板(≤10 列表 / ≤5k 成员,4 GB 内存、NVMe、SQLite 单机)——本文实测配置即此形态:

[mailman]
layout: custom
site_owner: owner@example.org

[paths.custom]
var_dir: /opt/mailman/var

[database]
class: mailman.database.sqlite.SQLiteDatabase
url: sqlite:////opt/mailman/var/data/mailman.db

[mta]
incoming: mailman.mta.postfix.LMTP
outgoing: mailman.mta.deliver.deliver
lmtp_host: 127.0.0.1
lmtp_port: 8024
smtp_host: 127.0.0.1
smtp_port: 25
configuration: /opt/mailman/etc/postfix-mailman.cfg

[webservice]
hostname: 127.0.0.1
port: 8001
admin_user: restadmin
admin_pass: <openssl rand -hex 16 生成>

[archiver.hyperkitty]
class: mailman_hyperkitty.Archiver
enable: yes
configuration: /etc/mailman3/mailman-hyperkitty.cfg

中站模板(10–100 列表,16 GB 内存,PostgreSQL + 独立归档机)——在上述基础上改:

[database]
class: mailman.database.postgresql.PostgreSQLDatabase
url: postgresql://mailman:强密码@db.internal:5432/mailman

[mta]
verp_delivery_interval: 1
max_delivery_threads: 4

并同步:settings.py 的 DATABASES 指向 PostgreSQL;HyperKitty 部署到独立主机时 mailman-hyperkitty.cfg 的 base_url 指向归档机;Core 与 Web 面凭据保持两端一致。

七、常见问题(FAQ)

Q1:改了 mailman.cfg 不生效。 先查查找顺序遮蔽(./var/etc/mailman.cfg、/var/etc/mailman.cfg 是否存在,存在即删);再确认重启了 mailman3 服务;最后用 mailman conf -k <键> 看生效值(第三章闭环)。

Q2:Postorius 报「无法连接 Mailman REST API」或 401。 settings.py 的 MAILMAN_REST_API_PASS 与 mailman.cfg [webservice] admin_pass 不一致(5.1 节实测 401 现象)。两端同值并分别重启。

Q3:消息被 SHUNT,日志 ModuleNotFoundError: No module named 'mailman.archiver(s)'。 归档器不在 Core 包内:pip install mailman-hyperkitty,class 必须写 mailman_hyperkitty.Archiver,并给出 configuration 指向插件配置;重启后 mailman unshunt 回收(安装篇 7.5 节完整实录)。

Q4:外站发信全 deferred,postfix 日志 Connection refused (port 8024)。 [mta] lmtp_port 与 /etc/postfix/transport 的 LMTP 端口错位(5.3 节实测复现)。两端对齐后 deferred 队列自动重投。

Q5:列表消息被莫名扣住。 看消息的 X-Mailman-Rule-Hits 头(5.6 节实测:max-size 命中即 held),再到 Postorius「待审请求」页或 REST held 接口处置;全局兜底调 [mta] max_recipients 与列表级 max_message_size。

Q6:Web 面访问 400 DisallowedHost。 settings.py 的 ALLOWED_HOSTS 缺该域名(5.7 节实测 400),补入域名保留 localhost/127.0.0.1,重启 mailman-web。

八、参考链接