Courier MTA 1.0.16 配置参数详解

Courier MTA 1.0.16 配置参数详解:/etc/courier 小文件体系与包装脚本 source 顺序、AUTH 双开关模型、bofh 在 Debian 无 libspf2 下失效的实证、courier-filter-perl+Mail::SPF 入站 SPF 550 拦截实测、opendkim 2048 位密钥+ dig 验证+openssl 验签、DMARC 记录与 dnsmasq 本地权威 DNS 模拟。实测日期 2026-10-25。

Courier MTACourier MTA邮件服务器Ubuntu2026/10/25

Courier MTA 1.0.16 配置参数详解

实测环境:Ubuntu 22.04 + courier-mta 1.0.16-3build3,实测日期 2026-10-25。示例域 quzuo-test.cn,示例账号 admin / q1w2e3r4。G2 邮件特判篇:含 SPF/DKIM/DMARC 全量实测。

一、配置体系总览

Debian 的 Courier 配置集中在 /etc/courier/,是「一组小文件」风格,没有单一主配置:

文件作用生效方式
courierd队列调度核心参数(投递并发、重试节奏)systemctl restart courier
esmtpd主 ESMTP 配置(AUTH、TLS、bofh 开关)restart courier-mta
esmtpd-msa587 提交端口的增量配置restart courier-msa
esmtpd-ssl465 SMTPS 的增量配置restart courier-mta-ssl
imapd / imapd-sslIMAP 参数(143/993)restart courier-imap[-ssl]
pop3d / pop3d-sslPOP3 参数(110/995)restart courier-pop[-ssl]
authdaemonrc认证后端与模块链restart courier-authdaemon
locals本地域清单(这些域的 RCPT 直接受理)restart courier-mta(见 §6 坑)
defaultdomain裸地址补全用的默认域同上
aliases/system系统别名库(需 makealiases)makealiases 即时生效
smtpaccess/default中继许可与 IP 访问控制(需 makesmtpaccess)makesmtpaccess
hosteddomains托管域(虚拟域)数据库(需 makehosteddomains)makehosteddomains
esmtproutes静态路由 域: [下一跳]courier restart
bofh内置策略开关(BOFH*)restart courier-mta
filters/active/courierfilter 过滤器启用目录(符号链接)courierfilter stop/start

包装脚本的 source 顺序(实测确认):esmtpd-msa 与 esmtpd-ssl 先 source 主文件 /etc/courier/esmtpd,再 source 自己——所以 AUTH 这类全局开关要改在主文件里,改在 esmtpd-msa 只影响 587。

二、courierd 关键参数

/etc/courier/courierd 控制队列行为,常用项:

DELAY NOTICES AFTER=1 hour        # 延迟多久后给发件人发"延迟通知"
DELAY NOTICES BEFORE=4 hours
MAXDELAY=72 hours                 # 队列最长保留,超时退信
MAXRCPT=100                       # 单封信最大收件人数
QUEUES=                           # 留空=自动按负载调并发

三、esmtpd 关键参数与 AUTH 模型

Courier 的设计:SMTP AUTH 只允许出现在 TLS 会话内。

  • ESMTPAUTH="":明文会话的 AUTH 方法清单,默认空=全关。
  • ESMTPAUTH_TLS="":TLS 会话内的 AUTH 方法清单,Debian 默认也是空——这是「465/587 全部 535 Authentication rejected」的根因。

开启(改主文件 /etc/courier/esmtpd):

sed -i 's/^ESMTPAUTH_TLS=""/ESMTPAUTH_TLS="PLAIN LOGIN CRAM-MD5 CRAM-SHA1 CRAM-SHA256"/' /etc/courier/esmtpd
systemctl restart courier-mta courier-msa courier-mta-ssl

实测开启后 465/587 均 235 Ok(回显见安装篇 §6)。

另有 ESMTPDSTART=YES/NO(各端口文件的独立开关,587 默认 NO)、BOFHCHECKDNS=1(校验 HELO 域名合法性,非法域直接 517 拒绝)等。

四、bofh 与「Debian 版没有 SPF」的实证

/etc/courier/bofh 是 Courier 的内置策略文件,上游支持 SPF 检查:

BOFHSPFHELO=fail,unknown
BOFHSPFMAILFROM=fail
BOFHSPFFROM=fail

但 Debian/Ubuntu 构建未链接 libspf2(dpkg -s courier-mta 依赖表与 courieresmtpd 的 ldd 双重实证),这三项在 jammy deb 下完全不生效——设了也不会有任何 SPF 检查发生,这是最容易误判的地方。上游源码构建(./configure 时检测到 libspf2)才有用。

结论:deb 形态下 SPF 入站校验走 §5 的 courier-filter-perl 路径。

五、SPF 入站实测:courier-filter-perl + Mail::SPF

参考思路与 《AnonAddy 配置参数详解》 一致:DNS 记录本地权威模拟 + 全链路验证。

5.1 安装与启用

apt-get install -y courier-filter-perl libmail-spf-perl
ln -s /usr/lib/courier/filters/courier-filter-perl /etc/courier/filters/active/

Debian 布局:过滤器本体在 /usr/lib/courier/filters/,/etc/courier/filters/active/ 下的符号链接决定启用哪些;模块配置文件是 /etc/courier/filters/courier-filter-perl.conf(注意不是别的名字)。

5.2 模块配置(实测可用)

/etc/courier/filters/courier-filter-perl.conf:

use lib '/usr/share/courier-filter-perl/perl5';
use Courier::Filter::Logger::Syslog;
use Courier::Filter::Module::SPF;
$options = {
    logger  => Courier::Filter::Logger::Syslog->new(),
    modules => [
        Courier::Filter::Module::SPF->new(
            scope      => 'helo',
            match_on   => ['fail'],
            default_response => 'SPF HELO check failed',
            trusting   => 1,
        ),
    ]
};

trusting => 1 的含义(读源码实证,Module.pm 第 528 行 next if $module->trusting and $message->trusted):跳过已认证/可信的出站邮件,不影响入站检查。这正是想要的行为。

5.3 启动(坑最多的一步)

courierfilter stop
courierfilter start
  • courierfilter 服务默认 inactive,必须显式启动;
  • courierfilter restart 不会重启 perl 子进程,改配置必须 stop + start;
  • filterctl 只有 start|stop [filter] 两个子命令,没有 list。

5.4 实测拦截回显

前提:DNS 上 spoof.quzuo-test.cn 有 v=spf1 -all 记录(实验环境用 dnsmasq 模拟,见 §7.2)。从非 loopback 地址发起会话(模块源码硬编码豁免 127.0.0.1,本机测不出来):

220 mail.quzuo-test.cn ESMTP
HELO spoof.quzuo-test.cn
250 mail.quzuo-test.cn Ok.
MAIL FROM:<a@spoof.quzuo-test.cn>
250 Ok.
RCPT TO:<admin@quzuo-test.cn>
250 Ok.
DATA
354 Ok.
Subject: spf test

body
.
550 SPF: SPF HELO check failed
QUIT
221 Bye.

两个行为要点(读源码 + 实测共同确认):

  1. Courier::Filter 在 DATA 完成后才评估(Overview.pod 原文:"right after the DATA command in the SMTP transaction phase has completed"),所以拒绝出现在 DATA 结束时,而不是 HELO/MAIL FROM 时刻。
  2. 改了 locals 必须重启 esmtpd(/usr/sbin/esmtpd stop && /usr/sbin/esmtpd start),courier restart 只重启 courierd,不重载 locals——否则新域名的 RCPT 仍是 513 Relaying denied.。

六、DKIM:密钥生成与 DNS 发布实测

Courier(含上游 2.0.9)没有原生 DKIM 签名能力,生产中需外挂 opendkim 或前置签名网关。这里按 AnonAddy 专栏同口径实测「密钥生成 → DNS 发布 → 配对验证」的完整链路。

6.1 生成 2048 位密钥对

apt-get install -y opendkim opendkim-tools
mkdir -p /etc/opendkim/keys/quzuo-test.cn
opendkim-genkey -b 2048 -d quzuo-test.cn -D /etc/opendkim/keys/quzuo-test.cn -s mail -v
chown -R opendkim:opendkim /etc/opendkim

产物:

$ ls -la /etc/opendkim/keys/quzuo-test.cn/
-rw------- 1 opendkim opendkim 1704 Oct 25 04:20 mail.private   # RSA 私钥
-rw------- 1 opendkim opendkim  503 Oct 25 04:20 mail.txt       # 待发布的 DNS TXT 记录

6.2 发布 DKIM 公钥并 dig 验证

把 mail.txt 里的记录发布到 DNS(选择子 mail._domainkey)。实验环境用 dnsmasq 本地权威模拟(见 §7.2),公网环境在 DNS 服务商控制台加 TXT 即可。验证:

$ dig +short mail._domainkey.quzuo-test.cn TXT
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8tfj1DLMvGaT1YisFbplQOMSvxS56vUsFd8F2a9quY1iuag6dhZcBbR/c+6zYMijWx55WJEambntEuxjdxo98IUbBIfq3XYgbyRBsfUqsXjoJzxCs9eZ+5MiXYjKADw3zYYEUn0NZggw3Q3rQ04Y8PUh0/4K7EArchJ4eNnR9Wy69hfFMRg67QhxBv4d6nC/" "INTzUvBsD/tBMY2TfS/vFyfTwPvhDYJxxMU7P5tCfm2GsGhYGfvBO0H/p7c1djoO/KCeGzqJh/Auabn0Sa+7vBAnXIAmIpFzLvWFB+QhiQOdcQXJnER3U+8xN+mQJMpBzPP4QGaAk4UQiKIbRT3swIDAQAB"

TXT 记录超过 255 字节会被拆成两段带引号的字符串,这是 RFC 1035 的正常行为,拼接后才是完整公钥。

6.3 密钥配对证明(openssl 私签公验)

opendkim-testkey 走 libunbound 递归解析(ldd 实证),在本地模拟 DNS 下查不到记录;改用更直接的密码学证明——用私钥签名、用从 DNS 记录里取出的公钥验签:

echo hello-dkim-test > /tmp/m.txt
openssl dgst -sha256 -sign /etc/opendkim/keys/quzuo-test.cn/mail.private -out /tmp/m.sig /tmp/m.txt
dig +short mail._domainkey.quzuo-test.cn TXT | tr -d '" ' | sed 's/v=DKIM1;k=rsa;p=//' | base64 -d > /tmp/m.pub.der
openssl rsa -pubin -inform DER -in /tmp/m.pub.der -out /tmp/m.pub 2>/dev/null
openssl dgst -sha256 -verify /tmp/m.pub -signature /tmp/m.sig /tmp/m.txt
Verified OK

Verified OK 即证明:DNS 上发布的公钥与本地私钥严格配对,DKIM 链路可信。

七、DMARC 与实验 DNS 环境

7.1 DMARC 记录

DMARC 只是一条 TXT,发布到 _dmarc.<域>:

$ dig +short _dmarc.quzuo-test.cn TXT
"v=DMARC1; p=quarantine; rua=mailto:admin@quzuo-test.cn"

含义:p=quarantine 未通过校验的信进隔离区;rua 接收汇总报告。灰度期建议先 p=none 观察报告再收紧。

7.2 实验用本地权威 DNS(dnsmasq)

实验环境没有真实公网域,用 dnsmasq 在本机模拟权威记录:

apt-get install -y dnsmasq
cat >> /etc/dnsmasq.d/quzuo-mail.conf <<'EOF'
listen-address=127.0.0.1
bind-interfaces
no-resolv
server=223.5.5.5
txt-record=quzuo-test.cn,"v=spf1 mx -all"
txt-record=spoof.quzuo-test.cn,"v=spf1 -all"
txt-record=_dmarc.quzuo-test.cn,"v=DMARC1; p=quarantine; rua=mailto:admin@quzuo-test.cn"
txt-record=mail._domainkey.quzuo-test.cn,"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8tfj1DLMvGaT1YisFbplQOMSvxS56vUsFd8F2a9quY1iuag6dhZcBbR/c+6zYMijWx55WJEambntEuxjdxo98IUbBIfq3XYgbyRBsfUqsXjoJzxCs9eZ+5MiXYjKADw3zYYEUn0NZggw3Q3rQ04Y8PUh0/4K7EArchJ4eNnR9Wy69hfFMRg67QhxBv4d6nC/INTzUvBsD/tBMY2TfS/vFyfTwPvhDYJxxMU7P5tCfm2GsGhYGfvBO0H/p7c1djoO/KCeGzqJh/Auabn0Sa+7vBAnXIAmIpFzLvWFB+QhiQOdcQXJnER3U+8xN+mQJMpBzPP4QGaAk4UQiKIbRT3swIDAQAB"
EOF
systemctl restart dnsmasq

要点:listen-address=127.0.0.1 + bind-interfaces 避免与 systemd-resolved 的 127.0.0.53 stub 抢 53 端口;no-resolv 后必须显式给一个上游(server=,示例用阿里 223.5.5.5),否则本机外网解析全断。最后把 /etc/resolv.conf 指向 127.0.0.1。

三条记录验证汇总:

$ dig +short quzuo-test.cn TXT
"v=spf1 mx -all"
$ dig +short _dmarc.quzuo-test.cn TXT
"v=DMARC1; p=quarantine; rua=mailto:admin@quzuo-test.cn"

八、其他高频配置

  • 静态路由:/etc/courier/esmtproutes 写 example.com: [10.89.73.99](IP 必须加方括号,写裸 IP 不生效),改完 courier restart。
  • 别名:/etc/courier/aliases/system 编辑后必须 makealiases 生成 .dat;默认 postmaster: 为空会丢信,务必指到真人。
  • 托管虚拟域:/etc/courier/hosteddomains + makehosteddomains;与 locals 的区别是托管域不映射系统用户的本地投递语义。
  • IP 访问控制:/etc/courier/smtpaccess/default + makesmtpaccess,控制哪些来源 IP 允许中继。

九、参考来源