
docker-mailserver 邮件域认证配置实战DKIM、DMARC 与 SPF 完整指南【免费下载链接】docker-mailserverProduction-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) running inside a container.项目地址: https://gitcode.com/gh_mirrors/do/docker-mailserverDKIM、DMARC、SPF 是防止邮件伪造spoofing、提升发件可信度的三大基础机制也是新部署 docker-mailserverDMS后必须完成的 DNS 侧配置。本文以 DMS 的 dkim_dmarc_spf.md 为骨架结合仓库内setup config dkim脚本、OpenDKIM/Rspamd 配置与 Postfix 启动脚本的源码实现带你完成密钥生成、DNS 记录发布、双后端选型OpenDKIM 与 Rspamd以及 SPF 白名单等全部落地步骤读完即可为自己的域名配置出可被验证、可排障的完整邮件认证链路。三种校验机制与 DMS 的实现选型在动手配置前先厘清三者的分工DKIMDomainKeys Identified Mail一种邮件认证方法用于检测伪造的发件人地址即邮件欺骗这类欺骗常被用于钓鱼和垃圾邮件。DMARCDomain-based Message Authentication, Reporting Conformance在 SPF/DKIM 之上定义当校验失败时该如何处理的域策略并支持接收方回报校验结果。SPFSender Policy Framework一种简单的邮件校验系统允许收件邮件服务器检查来自某域名的邮件是否由该域管理员授权的主机发出。DMS 从v12.0.0起集成了 Rspamd它可以作为邮件垃圾评分spam-score-calculation的一部分为收到的邮件执行 DKIM、DMARC、SPF 三项校验。同时 DMS 为每一项校验都保留了独立的替代实现供不使用 Rspamd 时选用校验项Rspamd 方案推荐独立方案DKIMRspamd 的 DKIM 模块opendkim以 milter 方式接入 Postfix与 Rspamd 方式一致DMARCRspamd 的 DMARC 模块opendmarc以 milter 方式接入 PostfixSPFRspamd 的 SPF 模块policyd-spf接入 Postfix 的smtpd_recipient_restrictions项目计划在未来的某个发行版中让 Rspamd 成为这些校验的默认实现届时会在移除上述独立方案前发布弃用通知deprecation notice。因此官方建议优先通过ENABLE_RSPAMD1使用 Rspamd 统一处理。需要留意 DNS 缓存与传播虽然现代 DNS 服务商响应很快但新增的 DNS 记录可能需要几分钟甚至几小时才能生效/传播配置后请耐心等待再验证。DKIM域密钥识别邮件DKIM 工作原理DKIM 启用后有两个方向的行为入站邮件DMS 会校验邮件中携带的 DKIM 签名出站邮件当发送域的 DKIM 密钥已配置时邮件会被签名。DKIM 依赖一对公私钥私钥用于给外发邮件签名公钥则发布到 DNS供接收方查询以验证签名是否可信。二者缺一不可。关于签名的有效期与 TLS 证书不同DKIM 密钥对本身没有固定的到期时间。但每封邮件的 DKIM 签名中可以携带一个过期时间接收方会拒绝验证已过期的签名——这是为了缓解DKIM 重放攻击攻击者利用第三方已投递且签名可信的邮件向其他会校验签名的 MTA 重发以绕过垃圾防护。与 TLS 握手验证的是未来通信的信任不同DKIM 签名是为了保证邮件在网络投递过程中未被篡改邮件一旦接收并验证通过事后重复验证的意义有限。关于密钥轮换你可以通过切换到新的 DKIM 选择器selector并更新 DNS 来实现轮换旧密钥与旧选择器在最后一封签名邮件的过期时间之前仍保持有效用于验证。DMS 不提供任何密钥轮换的自动化支持官方也指出对典型的小规模 DMS 部署而言轮换不太可能带来显著的安全收益。生成 DKIM 密钥前置条件执行前请确认已配置至少一个邮箱账户参见 account-management/overview.md已为 config 目录挂载持久化卷生成的文件需要写入本地存储参见 advanced/optional-config.md。新增任何新域名后都需要重复一次生成流程。基本命令在容器内执行以下命令即可用良好的默认参数生成 DKIM 密钥docker exec -it CONTAINER NAME setup config dkim如需自定义参数先查看help输出中支持的全部配置项与示例docker exec -it CONTAINER NAME setup config dkim help按照 help 输出的说明使用 LDAP 或 Rspamd 时你可能需要显式指定domain选项原因见下文多域名场景。调整密钥大小keysize当前生成的密钥对默认使用RSA-2048。这是一个合适的大小你可以下调到1024-bit或上调到4096-bit官方不鼓励因为属于过度设计。生成 1024-bit 密钥的命令setup config dkim keysize 1024根据 RFC 8301DKIM 密钥大小最好在 1024 到 2048 位之间。4096 位或更大的密钥可能无法兼容你邮件要送达的所有系统。官方建议通常不需要超过 2048 位如果 2048 位无法满足安全需求应优先考虑密钥轮换或改用 ECC椭圆曲线密钥而不是盲目加大 RSA 密钥。在源码层面OpenDKIM 路径的参数解析位于 target/bin/open-dkim脚本默认KEYSIZE2048、SELECTORmail支持keysize1024/2048/4096、selector、domain三个参数Rspamd 路径则见 target/bin/rspamd-dkim额外支持keytypersa/ed25519与--force/-v/-vv等选项。多域名场景显式指定 domainsetup config dkim默认只为主邮件域生成密钥主域是从 DMS 的 FQDN 去掉子域名后推导出的。例如 FQDN 为mail.example.com或example.com时默认会为example.com用户邮箱形如helloexample.com生成密钥。DKIM 生成逻辑无法查询 LDAP来获知其他邮件域。因此在使用LDAP以及Rspamd时必须显式指定附加域# ENABLE_OPENDKIM1默认 setup config dkim domain example.com,another-example.com # ENABLE_RSPAMD1 且 ENABLE_OPENDKIM0 setup config dkim domain example.com setup config dkim domain another-example.com注意当使用OpenDKIM 且ACCOUNT_PROVISIONERFILE默认配置时脚本会额外从setup email add添加的账户中自动检测邮件域并生成对应密钥。这一行为在 target/bin/open-dkim 的_generate_domains_config()中实现未传domain参数时调用_vhost_collect_postfix_domains收集 Postfix 虚拟域列表显式传入时则以逗号分隔的域名列表为准。两种签名后端OpenDKIM 与 RspamdDMS 的 DKIM 支持两种后端选择取决于你是否启用 Rspamd。OpenDKIM默认OpenDKIM 当前默认启用环境变量ENABLE_OPENDKIM默认值为 1见 environment.md。运行setup config dkim后新的 DKIM 密钥文件以及 OpenDKIM 配置会写入/tmp/docker-mailserver/opendkim/其中包括keys/domain/selector.private每个域的私钥PEM 编码与selector.txt公钥已格式化为 RFC 1035 DNS Zone 文件可用的 TXT 记录片段KeyTable选择器域名到私钥文件的映射SigningTable发件人通配规则到签名选择器的映射TrustedHosts可信主机列表默认写入127.0.0.1与localhost。重启生效修改后需要重建容器docker compose up --force-recreate此后外发邮件才会使用新 DKIM 密钥签名。从配置模板看OpenDKIM 使用relaxed/simple规范化、rsa-sha256签名算法以 milter 方式监听inet:8891localhost并排除Message-ID、Date、Return-Path、DKIM-Signature等头部不参与签名见 target/opendkim/opendkim.conf。启动阶段target/scripts/startup/setup.d/dmarc_dkim_spf.sh 会将/tmp/docker-mailserver/opendkim/的内容拷贝到/etc/opendkim/把inet:localhost:8891追加到 Postfix 的smtpd_milters与non_smtpd_milters并把容器/etc/resolv.conf中的 nameserver 写入/etc/opendkim.conf的Nameservers参数若未定义。Rspamd使用 Rspamd 需显式开启设置ENABLE_RSPAMD1见 environment.md并关闭默认的 OpenDKIMENABLE_OPENDKIM0。Rspamd 通过两个独立模块提供 DKIM 支持校验入站邮件的 DKIM 签名默认启用签名外发邮件需要额外配置密钥 DNS 配置。运行setup config dkim后主域密钥文件位于/tmp/docker-mailserver/rspamd/dkim/命名规则为domain-selector.private默认example.com-mail.private同时生成domain-selector.public.txt公钥与domain-selector.public.dns.txt可直接复制到 DNS 的 TXT 记录内容。基础的签名配置写入/tmp/docker-mailserver/rspamd/override.d/dkim_signing.conf有高级需求可手工修改。默认的dkim_signing.conf关键参数由 target/bin/rspamd-dkim 生成包括enabled true; sign_authenticated true; sign_local false; use_domain header; use_redis false; # 除非 Redis 也提供 DKIM 密钥否则不要修改 use_esld true; allow_username_mismatch true; check_pubkey true; # 初期建议开启用于检查公私钥是否匹配 try_fallback true; selector_map /tmp/docker-mailserver/rspamd/dkim_selectors.map; selector mail; path /tmp/docker-mailserver/rspamd/dkim/$domain-$selector.private;其中path模板中的$domain取自邮件From头$selector优先来自selector_map否则使用默认值。多域名时为每个域分别执行setup config dkim domain DOMAIN即可默认配置使用$domain-$selector路径模板因此一份dkim_signing.conf即可覆盖所有存在匹配密钥文件的域。自定义选择器会被记录在/tmp/docker-mailserver/rspamd/dkim_selectors.mapselector_map文件缺失会导致 Rspamd 加载失败脚本会始终保持一个空 map 存在见 target/bin/rspamd-dkim。从 OpenDKIM 迁移将/tmp/docker-mailserver/opendkim/keys/domain/selector.private复制为/tmp/docker-mailserver/rspamd/dkim/domain-selector.private即可。更早的 DMS Rspamd 版本生成的密钥命名为keytype-keysize-selector-domain.private.txt例如rsa-2048-mail-example.com.private.txt需重命名为新布局。Ed25519 密钥支持Rspamd 支持这一现代椭圆曲线但第三方对 Ed25519 DKIM 签名的验证支持并不可靠。注意Ed25519 与 RSA 不能共用同一个 selector每个 selector 只有一个 DNS TXT 记录。建议用不同的 selector 生成 RSA 兜底密钥然后在dkim_signing.conf中为特定域配置selectors数组实现双签名setup config dkim setup config dkim keytype ed25519 selector mail-ed25519domain { example.com { selectors [ { path /tmp/docker-mailserver/rspamd/dkim/example.com-mail.private; selector mail; }, { path /tmp/docker-mailserver/rspamd/dkim/example.com-mail-ed25519.private; selector mail-ed25519; } ] } }配置 DNS TXT 记录当你的邮件服务器发出带有 DKIM 签名的邮件时接收方需要查询 DNS 的TXT记录来验证签名是否可信。生成密钥时DNS 数据已保存到文件selector.txt默认mail.txt。将其内容更新到 DNS通过 Web 管理界面或直接编辑 DNS Zone 文件方式一Web 管理界面字段值TypeTXTNameselector._domainkey默认mail._domainkeyTTL使用默认值否则 3600 秒是合适的Data文件( ... )内的内容按下方建议格式化使用 Rspamd 时辅助脚本已直接输出你需要创建的 DNS 记录内容即 Data 字段直接复制粘贴即可。方式二DNS Zone 文件selector.txt本身就已格式化为可加入 DNS Zone 文件的片段直接复制粘贴进现有 zone 即可。TXT值已按每 255 个字符拆分成独立字符串以保证兼容性。selector.txt的格式化原理该文件是专为 DNS Zone 文件生成的文件名取自 DKIM selector默认 selector 为mail生成mail.txt。DKIM 需要在 DNS 建立TXT记录存储公钥而超过 255 字符的 TXT 值必须拆分成多段所以生成的selector.txt中公钥被拆成多段、每段用双引号包裹、整体放在( ... )之间mail._domainkey IN TXT ( vDKIM1; krsa; pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQMMqhb1S52Rg7VFS3EC6JQIMxNDdiBmOKZvY5fiVtD3Zyd9ZVV8e4IARVoMXWcJWSR6xkloitzfrRtJRwOYvmrcgugOalkmM0V4Gy/2aXeamuiBuUc4esDQEI3egmtAsHcVY1XCoYfs9VqoHEq3vdr3UQ8zP/lFP5UfcaJFCK/ZllqcO2P1GjIDVSHLdPpRHbMP/tU1a9mNZ 5QMZBJ/JuJK/s2bp8gpxKn8rh1akSQjlynlV9NI7J3CC7CUf3bGvoXIrb37C/lpJehS39KNtcGdaRufKauSfqx/7SxA0zyZCr13f7ASbMaQFzm/RRusTqozY/p/MsWx8QIDAQAB ) ;某些 DNS Web 界面会在内部自动处理分段反而可能要求你把值作为单行提供。此时需要取( ... )之间的内容把所有双引号包裹的片段拼接起来并去掉双引号及其间的空白。上述示例合并后为vDKIM1; krsa; pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQMMqhb1S52Rg7VFS3EC6JQIMxNDdiBmOKZvY5fiVtD3Zyd9ZVV8e4IARVoMXWcJWSR6xkloitzfrRtJRwOYvmrcgugOalkmM0V4Gy/2aXeamuiBuUc4esDQEI3egmtAsHcVY1XCoYfs9VqoHEq3vdr3UQ8zP/lFP5UfcaJFCK/ZllqcO2P1GjIDVSHLdPpRHbMP/tU1a9mNZ5QMZBJ/JuJK/s2bp8gpxKn8rh1akSQjlynlV9NI7J3CC7CUf3bGvoXIrb37C/lpJehS39KNtcGdaRufKauSfqx/7SxA0zyZCr13f7ASbMaQFzm/RRusTqozY/p/MsWx8QIDAQAB用dig验证新 DKIM 记录是否正确。TXT响应应为单行、多段、双引号包裹$ dig short TXT mail._domainkey.example.com vDKIM1; krsa; pMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQMMqhb1S52Rg7VFS3EC6JQIMxNDdiBmOKZvY5fiVtD3Zyd9ZVV8e4IARVoMXWcJWSR6xkloitzfrRtJRwOYvmrcgugOalkmM0V4Gy/2aXeamuiBuUc4esDQEI3egmtAsHcVY1XCoYfs9VqoHEq3vdr3UQ8zP/lFP5UfcaJFCK/ZllqcO2P1GjIDVSHLdPpRHbMP/tU1a9mNZ5QMZBJ/JuJK/s2bp8gpxKn8rh1akSQjlynlV9NI7J3CC7CUf3bGvoXIrb37C/lpJehS39 KNtcGdaRufKauSfqx/7SxA0zyZCr13f7ASbMaQFzm/RRusTqozY/p/MsWx8QIDAQABDKIM 排障可使用 MxToolbox 的 DKIM Verifier 或 uChecker 的 DKIM checker 检查 DKIM DNS 记录是否正确使用 Rspamd 时建议在dkim_signing.conf中开启check_pubkey true;。Rspamd 会校验私钥与公钥是否匹配如不匹配可在/var/log/mail/rspamd.log中查看具体错误。DMARC域消息认证报告与一致性DMS开箱即预配置了 DMARCENABLE_OPENDMARC默认启用。当使用 Rspamd 时可通过ENABLE_OPENDMARC0关闭额外且冗余的 DMARC 检查避免重复扣分。要在DNS 层面启用 DMARC唯一要做的是添加一条新的TXT记录。与 DKIM 不同DMARC 的 DNS 条目不需要任何密钥只需设置配置值即 DMARC 配置标签。你可以手工构造也可以使用现成的生成器。适合起步的宽松策略pnone仅收集报告不采取动作_dmarc.example.com. IN TXT vDMARC1; pnone; spnone; fo0; adkimr; aspfr; pct100; rfafrf; ri86400; ruamailto:dmarc.reportexample.com; rufmailto:dmarc.reportexample.com更严格的策略注意pquarantine与spquarantine校验失败将进入隔离/垃圾箱_dmarc.example.com. IN TXT vDMARC1; pquarantine; spquarantine; fo0; adkimr; aspfr; pct100; rfafrf; ri86400; ruamailto:dmarc.reportexample.com; rufmailto:dmarc.reportexample.com主要标签速查标签含义vDMARC1版本标识固定值pnone/pquarantine/preject主域策略不处理 / 隔离 / 拒绝sp...子域策略不设置则继承padkimr/adkimsDKIM 对齐模式宽松 / 严格aspfr/aspfsSPF 对齐模式宽松 / 严格pct100应用策略的邮件百分比ruamailto:.../rufmailto:...聚合报告 / 取证报告接收邮箱DMARC 状态可能因 DNS缓存延迟而无法立即显示。发布后可借助 Dmarcian 提供的工具验证 DNS 记录。从源码看DMARC 同样以 milter 方式接入 Postfix_setup_opendmarc()将inet:localhost:8893追加到smtpd_milters并用容器主机名更新/etc/opendmarc.conf的AuthservID与TrustedAuthservIDs。值得注意的实现细节是OpenDMARC milter 必须排在 OpenDKIM milter 之后先验证 DKIM 再评估 DMARC见 target/scripts/startup/setup.d/dmarc_dkim_spf.sh。SPF发件人策略框架SPF 通过 DNS 声明哪些主机被授权代表该域发送邮件。DMS 默认启用独立的policyd-spf服务ENABLE_POLICYD_SPF默认值为 1见 environment.md。如果 Rspamd 已接管 SPF 校验建议设置ENABLE_POLICYD_SPF0关闭默认服务避免重复处理。添加 SPF 记录在 DNS zone 中插入以下行example.com. IN TXT vspf1 mx ~all这条记录启用 SPF 的Softfail软失败模式。建议先以很低的 TTL发布该记录——SoftFail 是起步与测试阶段的合适设置它放行所有邮件只是在邮箱里把可疑邮件标记为垃圾。验证完成后可以考虑把 SPF 记录改为vspf1 mx -all以强制执行HardFail硬失败策略未授权主机发送的邮件将被拒绝。SPF 策略的更多细节可参考 open-spf.org 的 SPF Record Syntax 文档。无论采用哪种策略最后都应把 SPF 记录的 TTL 提升到最终值。源码层面_setup_policyd_spf()会在/etc/postfix/master.cf追加policyd-spf unix ... spawn userpolicyd-spf argv/usr/bin/policyd-spf服务设置policyd-spf_time_limit 3600并把check_policy_service unix:private/policyd-spf注入smtpd_recipient_restrictions中的reject_unauth_destination之后见 target/scripts/startup/setup.d/dmarc_dkim_spf.sh。Backup MX 与 Secondary MX为policyd-spf配置白名单如果你有 Backup MX 或 Secondary MX需要把它们的 IP 从 SPF 测试中白名单放行。方法是创建policyd-spf.conf配置文件并将其挂载到容器内的/etc/postfix-policyd-spf-python/policyd-spf.conf该路径对应policyd-spf.conf手册页。示例在docker-data/dms/config/postfix-policyd-spf.conf创建并编辑debugLevel 1 #0(仅错误)-4(完整接收数据) skip_addresses 127.0.0.0/8,::ffff:127.0.0.0/104,::1 # 白名单查找建议使用 IP 地址 Whitelist 192.168.0.0/31,192.168.1.0/30 # Domain_Whitelist mx1.not-example.com,mx2.not-example.com然后在compose.yaml中添加卷挂载volumes: - ./docker-data/dms/config/postfix-policyd-spf.conf:/etc/postfix-policyd-spf-python/policyd-spf.conf配置说明debugLevel日志详细程度0仅记录错误4记录完整接收数据skip_addresses跳过 SPF 检查的地址段默认含回环地址Whitelist直接放行的 IP 网段推荐用 IP 而非域名避免 DNS 解析开销Domain_Whitelist按域名放行示例中为注释状态适用于 mx1/mx2 这类 Backup MX 域名。测试与验证仓库内置了针对上述配置的自动化测试可作为你验证自身部署的参考OpenDKIM 路径setup config dkim的密钥生成、自定义域与自定义 selector、KeyTable/SigningTable 内容等均有覆盖见 test/tests/serial/open_dkim.batsRspamd 路径setup config dkim的 help 输出、默认/多域密钥生成、dkim_selectors.map条目、dkim_signing.conf默认配置、非法keytype报错等均有覆盖见 test/tests/parallel/set1/spam_virus/rspamd_dkim.bats。小结完整启用三大邮件认证机制的落地顺序可归纳为确认邮箱账户与 config 卷就绪选定后端默认 OpenDKIM或ENABLE_RSPAMD1ENABLE_OPENDKIM0使用 Rspamd执行setup config dkim多域时逐域加domain参数必要时调整keysize/selector/keytype将selector.txtOpenDKIM或脚本输出的 DNS 内容Rspamd发布为selector._domainkey的 TXT 记录并用dig验证发布_dmarc的 DMARC TXT 记录先pnone观察再逐步收紧发布vspf1 mx ~all或验证后收紧为-all有 Backup MX 时通过policyd-spf.conf白名单放行使用 MxToolbox/uChecker/Dmarcian 等工具复核记录确认生效。【免费下载链接】docker-mailserverProduction-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),仅供参考