已实现内容:发送给 *.me@toocent.cn 的内容自动转发给 wang.coder@foxmail.com
未实现内容:回复 *.me@toocent.cn 的转发内容,会被自动转发给源邮箱
用户让我总结本次对话的所有内容,形成一篇可以发表的文章。需要包括:
1. 目的
2. 方案
3. 遇到的坑
让我回顾一下整个过程:
1. 目的:在 1Panel 管理的 docker-mailserver 中添加邮件转发功能,将 *.me@toocent.cn 的邮件自动转发到 wang.coder@foxmail.com
2. 方案:
* 使用 Postfix 的 `virtual_alias_maps` 配合 `pcre` 正则表达式映射实现通配符转发
* 启用 SRS (Sender Rewriting Scheme) 解决 SPF 检查失败问题
* 创建持久化脚本确保容器重启后配置生效
3. 遇到的坑:
* Postfix 的 texthash 类型不支持通配符,需要使用 pcre/regexp 类型
* 转发后 SPF 检查失败(发件人地址仍然是原发件人,但服务器 IP 不在原发件人域名的 SPF 记录中)
* 需要启用 SRS 来重写发件人地址
* 域名没有 SPF 记录也会导致问题
* 容器重启后配置会丢失,需要持久化
我来写一篇详细的技术文章。
CodeFlicker
Docker-Mailserver 邮件转发配置实战:从踩坑到完美解决
一、背景与目的
近期项目中需要在运行于 1Panel 管理的 Docker 邮件服务器上添加邮件转发功能。具体需求如下:
* **需求**:将所有发送到 `*.me@toocent.cn` 的邮件自动转发到 `wang.coder@foxmail.com`
* **环境**:Docker-Mailserver(ghcr.io/docker-mailserver/docker-mailserver:15.1.0)运行在 1Panel 中
* **难点**:`*` 是通配符,需要匹配任意前缀
二、技术方案
2.1 环境分析
首先确认了邮件服务器的运行状态和配置:
# 查看运行中的容器
docker ps | grep mailserver
# 输出:
# 1Panel-mailserver-9FuA ghcr.io/docker-mailserver/docker-mailserver:15.1.0
关键配置目录挂载信息:
* 宿主机:`/opt/1panel/apps/mailserver/mailserver/data/dms/config`
* 容器内:`/tmp/docker-mailserver`
2.2 方案一:Postfix Virtual Alias Maps(失败)
最初尝试使用 Postfix 的 virtual_alias_maps,但发现:
# Postfix 配置检查
docker exec mailserver postconf virtual_alias_maps
# 输出:virtual_alias_maps = texthash:/etc/postfix/virtual
问题:texthash 类型不支持通配符,只能明确列出每个地址。这意味着如果要实现 *.me@toocent.cn 的转发,需要穷举所有可能的地址,这显然不现实。
2.3 方案二:PCRE 正则表达式映射(成功)
Postfix 支持 pcre(Perl Compatible Regular Expressions)类型的映射表,可以完美解决通配符问题。
# 确认 Postfix 支持 pcre
docker exec mailserver postconf -m | grep pcre
# 输出:pcre
实施步骤:
1. **创建 PCRE 映射文件**
在宿主机创建 /opt/1panel/apps/mailserver/mailserver/data/dms/config/postfix-virtual.pcre:
# 通配符转发:*.me@toocent.cn -> wang.coder@foxmail.com
/^[^@]+\.me@toocent\.cn$/ wang.coder@foxmail.com
正则表达式解析:
* `^[^@]+` - 匹配 @ 符号前的任意字符(至少一个)
* `\.me@` - 匹配 `.me@` 字符串
* `toocent\.cn$` - 匹配域名结尾
1. **更新 Postfix 配置**
# 复制文件到容器内
docker exec mailserver cp /tmp/docker-mailserver/postfix-virtual.pcre /etc/postfix/virtual.pcre
# 添加 pcre 映射到 virtual_alias_maps
docker exec mailserver postconf -e 'virtual_alias_maps = texthash:/etc/postfix/virtual, pcre:/etc/postfix/virtual.pcre'
# 重新加载 Postfix
docker exec mailserver postfix reload
1. **验证转发规则**
docker exec mailserver postmap -q "test.me@toocent.cn" pcre:/etc/postfix/virtual.pcre
# 输出:wang.coder@foxmail.com
docker exec mailserver postmap -q "hello.me@toocent.cn" pcre:/etc/postfix/virtual.pcre
# 输出:wang.coder@foxmail.com
docker exec mailserver postmap -q "no-reply@toocent.cn" pcre:/etc/postfix/virtual.pcre
# 输出:(空,不匹配)
三、遇到的坑
坑一:SPF 检查失败
现象:邮件确实被转发了,但被 QQ 邮箱拒绝:
status=bounced (host mx3.qq.com said: 550 SPF check failed)
日志分析:
# 邮件流程:
# 1. wang.coder@foxmail.com 发送邮件到 wang.me@toocent.cn
# 2. 服务器转发到 wang.coder@foxmail.com
# 3. 发件人仍然是 wang.coder@foxmail.com
# 4. QQ邮箱检查 SPF:服务器 IP (101.42.30.99) 不在 foxmail.com 的 SPF 记录中
# 5. 拒绝邮件
根本原因:邮件转发时,发件人地址没有改变。接收方(QQ邮箱)检查 SPF 记录时,发现邮件来自非授权服务器。
解决方案:启用 SRS(Sender Rewriting Scheme)
坑二:SRS 未启用
检查 SRS 状态:
docker exec mailserver env | grep -i srs
# 输出:
# SRS_SENDER_CLASSES=envelope_sender
# ENABLE_SRS=0 <-- 未启用
启用 SRS:
1. **生成密钥**:
docker exec mailserver bash -c 'openssl rand -base64 24 > /etc/postsrsd.secret && chmod 600 /etc/postsrsd.secret'
1. **修改 postsrsd 配置**:
docker exec mailserver sed -i 's/SRS_DOMAIN=localdomain/SRS_DOMAIN=toocent.cn/' /etc/default/postsrsd
1. **启动 postsrsd 服务**:
docker exec mailserver postsrsd -d toocent.cn -s /etc/postsrsd.secret -f 10001 -r 10002 -p /var/run/postsrsd.pid
1. **配置 Postfix 使用 SRS**:
docker exec mailserver postconf -e 'sender_canonical_maps = tcp:127.0.0.1:10001'
docker exec mailserver postconf -e 'sender_canonical_classes = envelope_sender'
docker exec mailserver postconf -e 'recipient_canonical_maps = tcp:127.0.0.1:10002'
docker exec mailserver postconf -e 'recipient_canonical_classes = envelope_recipient, header_recipient'
docker exec mailserver postfix reload
SRS 工作原理:
原始邮件:
From: wang.coder@foxmail.com
To: wang.me@toocent.cn
转发后(SRS 重写):
From: SRS0+xxxx=xx=foxmail.com=wang.coder@toocent.cn
To: wang.coder@foxmail.com
SPF 检查:检查 toocent.cn 的 SPF 记录(而非 foxmail.com)
坑三:域名缺少 SPF 记录
检查 SPF 记录:
host -t TXT toocent.cn
# 输出:toocent.cn has no TXT record
解决方案:在 DNS 服务商(DNSPod)添加 SPF 记录:
┌──────┬──────┬──────────────────────────────┐
│ 类型 │ 主机 │ 值 │
├──────┼──────┼──────────────────────────────┤
│ TXT │ @ │ v=spf1 ip4:101.42.30.99 -all │
└──────┴──────┴──────────────────────────────┘
或者更宽松的配置:
┌──────┬──────┬──────────────────┐
│ 类型 │ 主机 │ 值 │
├──────┼──────┼──────────────────┤
│ TXT │ @ │ v=spf1 a mx -all │
└──────┴──────┴──────────────────┘
坑四:容器重启后配置丢失
Docker 容器重启后,容器内的修改会丢失。需要持久化配置。
解决方案:使用 docker-mailserver 的 user-patches.sh 机制
创建 /opt/1panel/apps/mailserver/mailserver/data/dms/config/user-patches.sh:
#!/bin/bash
# 复制 pcre 虚拟映射文件到 Postfix 配置目录
cp /tmp/docker-mailserver/postfix-virtual.pcre /etc/postfix/virtual.pcre 2>/dev/null || true
# 配置 SRS (Sender Rewriting Scheme)
cp /tmp/docker-mailserver/postsrsd.secret /etc/postsrsd.secret 2>/dev/null || true
chmod 600 /etc/postsrsd.secret 2>/dev/null || true
# 启动 postsrsd
if [ -f /etc/postsrsd.secret ]; then
postsrsd -d toocent.cn -s /etc/postsrsd.secret -f 10001 -r 10002 -p /var/run/postsrsd.pid 2>/dev/null || true
fi
# 配置 Postfix 使用 SRS
postconf -e 'sender_canonical_maps = tcp:127.0.0.1:10001' 2>/dev/null || true
postconf -e 'sender_canonical_classes = envelope_sender' 2>/dev/null || true
postconf -e 'recipient_canonical_maps = tcp:127.0.0.1:10002' 2>/dev/null || true
postconf -e 'recipient_canonical_classes = envelope_recipient, header_recipient' 2>/dev/null || true
# 重新加载 Postfix
postfix reload 2>/dev/null || true
同时创建 postfix-main.cf 用于持久化 Postfix 配置:
# 通配符转发配置
virtual_alias_maps = texthash:/etc/postfix/virtual, pcre:/etc/postfix/virtual.pcre
# SRS (Sender Rewriting Scheme) 配置
sender_canonical_maps = tcp:127.0.0.1:10001
sender_canonical_classes = envelope_sender
recipient_canonical_maps = tcp:127.0.0.1:10002
recipient_canonical_classes = envelope_recipient, header_recipient
四、最终配置文件清单
/opt/1panel/apps/mailserver/mailserver/data/dms/config/
├── postfix-accounts.cf # 邮箱账户配置
├── postfix-main.cf # Postfix 自定义配置(持久化)
├── postfix-virtual.pcre # PCRE 转发规则
├── postsrsd.secret # SRS 密钥
└── user-patches.sh # 容器启动脚本
五、验证测试
# 检查 postsrsd 运行状态
docker exec mailserver ps aux | grep postsrsd
# 输出:postsrsd -d toocent.cn -s /etc/postsrsd.secret ...
# 检查端口监听
docker exec mailserver ss -tlnp | grep -E '10001|10002'
# 输出:
# LISTEN 127.0.0.1:10001 (postsrsd)
# LISTEN 127.0.0.1:10002 (postsrsd)
# 检查 Postfix 配置
docker exec mailserver postconf | grep -E 'sender_canonical|recipient_canonical|virtual_alias'
# 输出:
# sender_canonical_maps = tcp:127.0.0.1:10001
# recipient_canonical_maps = tcp:127.0.0.1:10002
# virtual_alias_maps = texthash:/etc/postfix/virtual, pcre:/etc/postfix/virtual.pcre
六、总结
本次配置涉及的关键技术点:
┌──────────────┬───────────────────────────────────┐
│ 问题 │ 解决方案 │
├──────────────┼───────────────────────────────────┤
│ 通配符转发 │ PCRE 正则表达式映射 │
├──────────────┼───────────────────────────────────┤
│ SPF 检查失败 │ 启用 SRS 重写发件人地址 │
├──────────────┼───────────────────────────────────┤
│ 域名缺少 SPF │ 添加 TXT 记录 │
├──────────────┼───────────────────────────────────┤
│ 配置持久化 │ user-patches.sh + postfix-main.cf │
└──────────────┴───────────────────────────────────┘
注意事项:
1. SRS 的 secret 密钥需要妥善保存,更换后之前重写的地址将无法退信
2. SPF 记录是邮件送达的基础,必须配置正确
3. 建议同时配置 DKIM 和 DMARC 以提高邮件送达率
4. 定期检查邮件日志,监控转发状态
参考文档:
* [Docker-Mailserver 官方文档](https://docker-mailserver.github.io/docker-mailserver/)
* [Postfix PCRE Table](http://www.postfix.org/pcre_table.5.html)
* [Sender Rewriting Scheme](https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme)
