Mailman3 安装与部署
记录 Mailman3 组件架构、部署流程与常用端口配置,帮助快速完成邮件列表服务搭建。
一、整体架构说明#
Postfix --> Mailman Core --> HyperKitty (Archiver)
|
+--> REST API (8001)
|
+--> Postorius (Web 管理)css- Mailman Core:负责邮件列表逻辑、投递、归档调度
- Postorius:列表管理 Web UI
- HyperKitty:邮件归档与 Web 展示
- Mailman-Web:Django 项目,包含 Postorius + HyperKitty
- Nginx:对外 Web 入口(8090)
关键端口规划
| 服务 | 端口 | 说明 |
|---|---|---|
| Mailman REST | 8001 | 仅本机访问 |
| Mailman Web | 8000 | Gunicorn 内部 |
| Nginx Web | 8090 | 对外访问 |
二、Mailman Core 安装#
2.1 安装系统依赖(Rocky Linux 10)#
sudo dnf update -y
sudo dnf install -y \
git gcc make \
python3 python3-devel python3-pip \
libffi-devel openssl-devel \
postfix \
mariadb-connector-c-devel \
nginx
bash说明:Mailman Core/ Web 都是 Python 项目;生产环境强烈建议用独立虚拟环境和专用系统用户。
2.2 创建专用用户与目录#
sudo useradd -r -m -d /opt/mailman -s /sbin/nologin mailman
sudo mkdir -p /opt/mailman/{venv,core,web,var,logs,etc}
sudo chown -R mailman: mailman /opt/mailmanshell2.3 建虚拟环境#
sudo -u mailman python3 -m venv /opt/mailman/venv
sudo -u mailman /opt/mailman/venv/bin/pip install -U pip wheel setuptoolsbashclone 仓库再安装
sudo -u mailman git clone https://gitlab.com/mailman/mailman.git /opt/mailman/core
sudo -u mailman /opt/mailman/venv/bin/pip install -e /opt/mailman/corebashMailman Core 的安装与运行结构、命令行(
mailman start|stop|shell)以官方安装文档为基准。
2.4 配置 Mailman Core(mailman. Cfg)#
把主配置放到 /opt/mailman/etc/mailman.cfg(自建目录更清晰)。
最终配置为:
[paths.custom]
var_dir: /opt/mailman/var
[mailman]
layout: custom
site_owner: wanghh@example.com
# Mailman 的 var_dir:队列、数据、生成的 postfix map 等
[mta]
incoming: mailman.mta.postfix.LMTP
outgoing: mailman.mta.deliver.deliver
# Postfix 投递给 Mailman 用 LMTP(推荐 8024 之类高端口)
lmtp_host: 127.0.0.1
lmtp_port: 8024
# Mailman 发信走 Postfix(本机 25)
smtp_host: 127.0.0.1
smtp_port: 25
[database]
# 生产强烈建议用 PostgreSQL
# 这里给 PostgreSQL 的写法示意:
class: mailman.database.postgresql.PostgreSQLDatabase
url: postgresql://mailman:123456@127.0.0.1:5432/mailman
[logging]
config: /opt/mailman/etc/logging.cfg
[rest]
username: restadmin
password: restpass
[archiver.hyperkitty]
class: mailman_hyperkitty.Archiver
enable: yes
configuration: /opt/mailman/etc/hyperkitty.cfgini此处应注意 var_dir: /opt/mailman/var ,设置为本地默认路径,避免路径错误。另外,直接运行 mailman 3 不要在 root 目录下,可能会是程序将当前路径加载进程序,导致权限问题或其他问题。
三、Mailman 3 与原有邮件服务器协同工作#
Postfix / Dovecot 基于虚拟用户使用
3.1 整体架构#
在 虚拟用户环境 下,正确的职责划分是:
外部邮件
↓
Postfix
├─ 普通邮箱(user@example.com) → virtual_mailbox_maps → Dovecot
└─ 列表邮箱(list@lists.example.com)
→ transport_maps → lmtp:127.0.0.1:8024 → Mailman Corecss- 用 transport_maps 把“列表域 / 列表地址”优先交给 Mailman
- Mailman 自动生成 Postfix maps
- Postfix 只“引用”这些 map,不自己维护列表
3.2 Mailman 3 生成 Postfix map#
Mailman Core 在运行后,会在它的 var_dir 下生成 Postfix 可用的映射文件
在Mailman 侧:启用 Postfix MTA 接口#
[mta]
incoming: mailman.mta.postfix.LMTP
outgoing: mailman.mta.deliver.deliver
# Postfix 投递给 Mailman 用 LMTP(推荐 8024 之类高端口)
lmtp_host: 127.0.0.1
lmtp_port: 8024
# Mailman 发信走 Postfix(本机 25)
smtp_host: 127.0.0.1
smtp_port: 25ini然后确认 Mailman 正常运行后,生成了 map:
ls -l /opt/mailman/var/data/
total 72
-rw-rw----. 1 mailman mailman 349 Feb 3 10:42 postfix_domains
-rw-r-----. 1 mailman mailman 32768 Feb 3 10:42 postfix_domains.lmdb
-rw-rw----. 1 mailman mailman 988 Feb 3 10:42 postfix_lmtp
-rw-r-----. 1 mailman mailman 32768 Feb 3 10:42 postfix_lmtp.lmdbbash如果这个目录不存在,说明 Mailman 还没真正启动成功。 也可以指定生成 map 文件:
sudo -u mailman -H /opt/mailman/venv/bin/mailman -C /opt/mailman/etc/mailman.cfg aliasesbashPostfix 侧:正确引用 Mailman 生成的 map#
在虚拟用户场景下:
virtual_mailbox_maps:只管真实邮箱transport_maps:优先级更高,用来“劫持”列表地址local_recipient_maps:要么关闭,要么确保不拒绝列表地址 修改 Postfix/etc/postfix/main.cf推荐配置
# for mailman
local_recipient_maps = lmdb:/opt/mailman/var/data/postfix_lmtp,
$alias_maps,
lmdb:/etc/postfix/virtual-mailbox
relay_domains = lmdb:/opt/mailman/var/data/postfix_domains
transport_maps = lmdb:/opt/mailman/var/data/postfix_lmtpini在 Rocky/RHEL 系现在更推荐 lmdb:,而不是 hash:(db3/bdb 经常被拆包或默认不带)
生成 map#
Mailman 生成的是 文本文件,Postfix 用时必须 postmap:
sudo postmap lmdb:/opt/mailman/var/data/postfix_domains
sudo postmap lmdb:/opt/mailman/var/data/postfix_lmtpbash验证 Postfix transport 是否命中:
postmap -q lists.example.com /opt/mailman/var/data/postfix_domainsbash也可查看日志:
tail -f /var/log/maillogbashsystemd 管理 Mailman Core#
创建 systemd unit:/etc/systemd/system/mailman.service
[Unit]
Description=GNU Mailman Core
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=mailman
Group=mailman
WorkingDirectory=/opt/mailman
Environment=HOME=/opt/mailman
# 关键:systemd 直接跟踪 master 进程
ExecStart=/opt/mailman/venv/bin/master -C /opt/mailman/etc/mailman.cfg
# 让 systemd 用 SIGTERM 停止(默认也是 SIGTERM)
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.targetini重载并重启:
sudo systemctl daemon-reload
sudo systemctl reset-failed mailman
sudo systemctl restart mailman
sudo systemctl status mailman --no-pagerbash四、部署 Mailman Web#
Mailman Web 实际是一个 Django 项目,由三部分组成:
┌──────────────┐
│ Postorius │ ← 列表管理 UI
├──────────────┤
│ HyperKitty │ ← 邮件归档 UI
├──────────────┤
│ mailman-web │ ← Django 项目本体
└──────┬───────┘
│ REST
▼
┌──────────────────┐
│ Mailman Core │ ← 你已经跑起来了
└──────────────────┘css4.1 安装 web#
直接复用 /opt/mailman/venv,这样版本和依赖最干净。
sudo -u mailman -H /opt/mailman/venv/bin/pip install -U \
mailman-web \
postorius \
hyperkitty
# 验证
sudo -u mailman -H /opt/mailman/venv/bin/pip show mailman-web postorius hyperkittyplaintext创建 mailman-web Django 项目配置 1、 创建配置目录
sudo mkdir -p /opt/mailman/web
sudo chown -R mailman:mailman /opt/mailman/web
sudo mkdir -p /opt/mailman/web/logs
sudo chown -R mailman:mailman /opt/mailman/web/logs
sudo chmod 750 /opt/mailman/web/logs
sudo mkdir -p /opt/mailman/var/logs
sudo chown -R mailman:mailman /opt/mailman/var/logs
sudo chmod 750 /opt/mailman/var/logs
bash2、生成默认 Django 配置 /opt/mailman/web/settings.py
# Mailman Web configuration (custom location)
from mailman_web.settings.base import *
from mailman_web.settings.mailman import *
# ---- Basic ----
DEBUG = False
ALLOWED_HOSTS = ["192.168.52.46", "127.0.0.1", "localhost"]
SECRET_KEY = "f1a3696c-961e-4133-ad1a-2c7fcb5e5722"
# --- static files ---
STATIC_URL = "/static/"
STATIC_ROOT = "/opt/mailman/web/static"
# 如果用 compressor offline,建议保留:
COMPRESS_OFFLINE = True
# ---- Database (建议单独建一个库) ----
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "mailmanweb",
"USER": "mailman",
"PASSWORD": "123456",
"HOST": "127.0.0.1",
"PORT": "5432",
}
}
# ---- Connect to Mailman Core REST (与你 mailman.cfg 一致) ----
MAILMAN_REST_API_URL = "http://127.0.0.1:8001/"
MAILMAN_REST_API_VERSION = "3.1"
MAILMAN_REST_API_USER = "restadmin"
MAILMAN_REST_API_PASS = "restpass"
# 归档页面 URL
HYPERKITTY_URL = "http://127.0.0.1/hyperkitty/"
#HYPERKITTY_API_KEY = "59ebff6c-3f00-4991-8125-e3a3b28907c7"
MAILMAN_ARCHIVER_KEY = "59ebff6c-3f00-4991-8125-e3a3b28907c7"
CSRF_TRUSTED_ORIGINS = [
"http://192.168.52.46:8090",
]
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'http')
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = Falsepython3、PostgreSQL 创建 mailmanweb 数据库(如果还没建)
sudo -u postgres psql -c "CREATE DATABASE mailmanweb OWNER mailman;"plaintext4、 初始化 Django(迁移 + 管理员 + 静态文件) 后面所有命令都用同一个环境变量:
export MAILMAN_WEB_CONFIG=/opt/mailman/web/settings.pybash迁移数据库
sudo -u mailman -H env MAILMAN_WEB_CONFIG=/opt/mailman/web/settings.py \
/opt/mailman/venv/bin/mailman-web migratebash创建 Web 超级管理员
sudo -u mailman -H env MAILMAN_WEB_CONFIG=/opt/mailman/web/settings.py \
/opt/mailman/venv/bin/mailman-web createsuperuserbash收集静态文件 :
sudo -u mailman -H \
PYTHONPATH=/opt/mailman/web \
DJANGO_SETTINGS_MODULE=settings \
/opt/mailman/venv/bin/django-admin collectstaticbash尝试运行:
sudo -u mailman -H \
PYTHONPATH=/opt/mailman/web \
DJANGO_SETTINGS_MODULE=settings \
/opt/mailman/venv/bin/django-admin runserver 127.0.0.1:8000bash5、用 gunicorn 跑 mailman-web(systemd)
创建 systemd 服务文件 /etc/systemd/system/mailman-web.service
[Unit]
Description=Mailman3 Web (Postorius + HyperKitty) via Gunicorn
After=network.target
[Service]
Type=simple
User=mailman
Group=mailman
WorkingDirectory=/opt/mailman/web
Environment="PYTHONPATH=/opt/mailman/web"
Environment="DJANGO_SETTINGS_MODULE=settings"
# 如果 settings.py 里还保留了 MAILMAN_WEB_CONFIG 机制,不用也行;
# 但避免混乱,生产建议只用 DJANGO_SETTINGS_MODULE 即可。
ExecStart=/opt/mailman/venv/bin/gunicorn \
--bind 127.0.0.1:8000 \
--workers 3 \
--timeout 120 \
--access-logfile /opt/mailman/web/logs/gunicorn_access.log \
--error-logfile /opt/mailman/web/logs/gunicorn_error.log \
wsgi:application
Restart=on-failure
RestartSec=3
# 让 gunicorn 读到必要路径
UMask=0027
[Install]
WantedBy=multi-user.targetini启动:
sudo systemctl daemon-reload
sudo systemctl enable --now mailman-web
systemctl status mailman-web --no-pagerbash4.2 Nginx 反向代理#
创建 /etc/nginx/conf.d/mailman-web.conf:
server {
listen 8090;
server_name 192.168.52.46;
# 静态文件(关键:解决样式简陋)
location /static/ {
alias /opt/mailman/web/static/;
expires 7d;
add_header Cache-Control "public";
}
# Web 反代(Postorius/HyperKitty)
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}ini重启 nginx :
sudo nginx -t
sudo systemctl reload nginxbash4 .3 HyperKitty 与 mailman 互通#
Mailman 的配置文件需要配置 HyperKitty 信息,/opt/mailman/etc/mailman.cfg:
[archiver.hyperkitty]
class: mailman_hyperkitty.Archiver
enable: yes
configuration: /opt/mailman/etc/hyperkitty.cfgini其中,/opt/mailman/etc/hyperkitty.cfg 中内容为:
[general]
base_url: http://127.0.0.1:8090/hyperkitty/
api_key: 59ebff6c-3f00-4991-8125-e3a3b28907c7iniDjango 也需配置 /opt/mailman/web/settings.py:
# 归档页面 URL
HYPERKITTY_URL = "http://127.0.0.1/hyperkitty/"
#HYPERKITTY_API_KEY = "59ebff6c-3f00-4991-8125-e3a3b28907c7"
MAILMAN_ARCHIVER_KEY = "59ebff6c-3f00-4991-8125-e3a3b28907c7"python