- 后端
- 通信
【免费下载链接】Mailu
Insular email distribution - mail server as Docker images
Mailu 使用 Rspamd 作为其垃圾邮件过滤引擎,对每一封经过 Postfix 的邮件进行实时评分、标记与拦截。本文围绕 docs/antispam.rst 展开,完整讲解 Rspamd 的评分分级策略、Dovecot 依据用户偏好将邮件分类到 Junk 文件夹的原理、批量学习已有邮箱中的 ham/spam、基于 multimap 的域名级黑名单,以及可执行附件与宏扫描的定制方法,帮助你精确控制邮件流的过滤行为。
一、Mailu 的垃圾邮件过滤体系总览
Mailu 使用 Rspamd 进行垃圾邮件过滤。Rspamd 是一个快速、免费、开源的垃圾邮件过滤系统,部署在 antispam 容器中。整个过滤链路的核心参与者有三个:
- Postfix(SMTP 服务):所有收发的邮件都会经过 Postfix,由它把邮件交给 Rspamd 扫描;
- Rspamd(antispam 容器):执行规则打分、病毒检测与宏扫描,并依据分值决定是放行、加头、灰名单还是拒收;
- Dovecot(IMAP/LMTP 投递服务):读取 Rspamd 写入的邮件头,结合用户设置的"垃圾邮件过滤容差",通过 Sieve 脚本把邮件放入收件箱或 Junk 文件夹。
二、Rspamd 评分分级:0–15 分制下的默认行为
Mailu 中 Rspamd 使用 0 到 15 的评分刻度。以下为默认值,可在 Rspamd WebUI 的 configuration 标签页中调整:
| 邮件评分 | 默认处理行为 |
|---|---|
| 15 分及以上 | 拒收(reject) |
| 6 分及以上 | 邮件头中写入垃圾邮件评分(加头) |
| 4 分及以上 | 灰名单(greylist) |
| 3 分及以下 | 接受(accept) |
评分刻度的上限15在 core/dovecot/conf/dovecot.conf 中有明确佐证:Dovecot 通过sieve_spamtest_status_type = strlen、sieve_spamtest_status_header = X-Spam-Level与sieve_spamtest_score_max_value = 15从邮件头解析评分,这与文档中"0–15 分"的设定完全一致。
评分流程与加头示例
当一封邮件被 Postfix 接收或发送时,Rspamd 对其进行扫描。如果评分落在 6 到 15 之间,Rspamd 会在邮件头中追加垃圾邮件评分信息。以下是一个评分为 14 的邮件头示例(摘自原文档):
X-Spamd-Bar: ++++++++++++++ X-Spam-Level: ************** Authentication-Results: test.mailu.io; dkim=pass header.d=example.com header.s=mailing header.b=ABCDE; dkim=pass header.d=example.com header.s=mailing header.b=ABCDE; dmarc=pass (policy=none) header.from=eventim.de; spf=pass (test.mailu.io: domain of return@example.com designates 11.22.33.44 as permitted sender) smtp.mailfrom=return@example.com X-Spam: Yes其中X-Spam-Level是后续 Dovecot 分类的关键依据(星级数量对应评分值)。
三、Dovecot 投递分类:用户级"垃圾邮件过滤容差"
Rspamd 负责评分,而把邮件投递到哪个文件夹则由 Dovecot 依据用户偏好决定。其工作方式如下:
开启垃圾邮件过滤:在管理后台的 Settings → Antispam 中勾选Enable spam filter。如果该选项被关闭,那么除了评分 15 及以上被 Rspamd 直接拒收的邮件外,其余所有邮件都会自动进入收件箱。该选项在数据库中以
spam_enabled字段存储(见 core/admin/mailu/models.py),默认值为True。配置过滤容差:在管理后台的 Antispam 设置中,用户可自定义垃圾邮件过滤容差(spam filter tolerance),默认值为 80%。容差越低,误判越多(正常邮件被当作垃圾),用户可通过降低该值微调"何时将邮件判定为垃圾"。该字段对应 core/admin/mailu/models.py 中的
spam_threshold,默认值来自环境变量DEFAULT_SPAM_THRESHOLD(默认 80)。百分比换算与比较:Dovecot 从邮件头中提取
X-Spam-Level,把 0–15 的评分换算为 0–100 的百分比(评分 ÷ 15 × 100),再与用户定义的容差比较。判定逻辑为:
如果 <邮件评分的百分比> 大于 <垃圾邮件过滤容差>,则把邮件移入垃圾邮件文件夹并标记为已读。一个具体的例子
假设用户把过滤容差设为默认的 80%,某封邮件的评分为 10:
- 百分比换算:10 ÷ 15 ≈ 66%;
- 66% < 80%,因此这封邮件被判定为 ham,进入收件箱;
- 如果用户希望 66% 评分的邮件也被归入垃圾邮件,可在管理后台把容差降到 65%。
新用户的默认容差:DEFAULT_SPAM_THRESHOLD
新用户默认使用的过滤容差由环境变量DEFAULT_SPAM_THRESHOLD控制(默认 80),定义见 docs/configuration.rst。从源码看,该变量在创建用户时作为spam_threshold列的默认值被读取(core/admin/mailu/models.py)。
底层机制:Sieve 脚本如何落地判定
上述逻辑最终由一份由管理端动态渲染的 Sieve 脚本执行,模板位于 core/admin/mailu/internal/templates/default.sieve:
{% if user.spam_enabled %} if spamtest :percent :value "gt" :comparator "i;ascii-numeric" "{{ user.spam_threshold }}" { {% if user.spam_mark_as_read %} setflag "\\seen"; {% endif %} fileinto :create "Junk"; stop; } {% endif %}可以看到:只有spam_enabled开启时才执行判定;当spamtest百分比大于spam_threshold时,把邮件fileinto到 Junk 文件夹,并(在spam_mark_as_read开启时)标记为已读。这与原文档描述的行为完全对应。管理端还通过 API 提供spam_enabled、spam_threshold、spam_mark_as_read字段的读写(见 core/admin/mailu/api/v1/user.py),后台界面对应 core/admin/mailu/ui/templates/user/settings.html 的表单控件。
四、自动学习:从既有邮箱批量训练 ham 与 spam
Mailu 支持对移入 Junk 文件夹的邮件进行自动学习:
- 任何移入 Junk 文件夹的邮件都会被重新学习为spam;
- 任何从 Junk 移出到其他文件夹(Trash 除外)的邮件都会被重新学习为ham。
该能力由 Dovecot 的 imapsieve 机制实现:Dovecot 在 core/dovecot/conf/dovecot.conf 中为 Junk 邮箱配置了report-spam(COPY/APPEND 时触发,调用 core/dovecot/conf/report-spam.sieve)与imapsieve_from Junk(COPY 出 Junk 时触发,调用 core/dovecot/conf/report-ham.sieve)。真正的学习动作由 core/dovecot/conf/spam.script 与 core/dovecot/conf/ham.script 完成,它们调用rspamc分别执行learn_spam/learn_ham,并通过模糊哈希(fuzzy)加/删实现细粒度更新。
批量学习已有邮箱中的邮件
如果你已经有一个既有邮箱,并希望 Mailu 把它们全部学习为 ham,可以在 dovecot 容器内运行rspamc:
rspamc -h antispam:11334 -P mailu -f 13 fuzzy_add /mail/user\@example.com/.Ham_Learn/cur/ rspamc -h antispam:11334 -P mailu learn_ham /mail/user\@example.com/.Ham_Learn/cur/这会把Ham_Learn文件夹中的每个文件都学习为 ham。同理,把Spam_Learn文件夹中的全部邮件学习为 spam:
rspamc -h antispam:11334 -P mailu -f 11 fuzzy_add /mail/user\@example.com/.Spam_Learn/cur/ rspamc -h antispam:11334 -P mailu learn_spam /mail/user\@example.com/.Spam_Learn/cur/参数说明:
-h antispam:11334:Rspamd 控制端口地址与端口。从 core/rspamd/conf/worker-controller.inc 可见控制端口绑定在*:11334,密码为mailu(即-P mailu);-f 11/-f 13:fuzzy 存储中 spam(11)与 ham(13)两个哈希集合的编号。这与 core/rspamd/conf/metrics.conf 中的LOCAL_FUZZY_*符号、以及 ham/spam 脚本中fuzzy_del/fuzzy_add的用法相互印证;- 路径中的
@需转义为\@,邮件数据目录通常位于/mail/之下。
五、按域名黑名单:multimap 过滤器实战
通过 Rspamd 的 multimap 过滤器,可以按发送方域名阻止邮件。要启用自定义符号(规则),需要利用Rspamd overrides 文件夹:把配置文件放到宿主机$ROOT/overrides/rspamd/目录,该目录会被映射到容器的/overrides。
关于 overrides 的通用约定,可参考 docs/faq.rst 中的 "How can I override settings?":Postfix、Dovecot、Nginx 与 Rspamd 均支持在
$ROOT/overrides下放置覆盖配置,Rspamd 对应rspamd子目录中的所有文件;在 compose 部署中,$ROOT/overrides/rspamd以只读方式挂载到容器内(见 docs/compose/docker-compose.yml)。
第一步:创建 multimap 过滤器配置
在overrides/rspamd/下创建multimap.conf。由于该文件会被 Rspamd 的 core/rspamd/conf/multimap.conf 通过.include(try=true,priority=1,duplicate=merge) "/overrides/multimap.conf"合并进主配置,因此不需要再写multimap {}元素:
#override.d/multimap.conf #Tip: Each setting must be closed with a semi-colon ';'. local_bl_domain { type = "from"; filter = "email:domain"; map = "/overrides/blacklist.inc"; score = 14; description = "Senders domain part is on the local blacklist"; group = "local_bl"; action = "reject"; }注意其中的action = "reject";:这是一条预过滤器(pre-filter)。一旦使用 pre-filter,命中的邮件不再经过后续任何过滤器/规则的进一步处理。如果省略action行,则配置的score会被累加到邮件总分上,最终由处理完所有规则后的总分决定判定结果。可用的action取值与语义如下:
| action | 含义 |
|---|---|
discard | 丢弃邮件,但对发件方返回投递成功(仅在特殊场景使用) |
reject | 拒收邮件,实现真正意义上的域名封禁 |
add header | 添加垃圾邮件头标记,把评分写入邮件头,随后依据用户过滤容差决定进收件箱还是 Junk |
no action | 放行邮件,且不写入任何评分头,可用于构建白名单过滤器 |
soft reject | 临时延迟邮件(例如用于灰名单或限速) |
要把邮件移入 Junk(Spam)文件夹,可用评分15配合action = "add header"。上面的示例配置会拒收所有列在/overrides/blacklist.inc中的域名发来的邮件。
第二步:创建域名黑名单映射
在overrides/rspamd/下创建blacklist.inc,每行一个域名,可用#添加注释:
#Blacklisted domains. All emails from these domains are blacklisted and will be rejected. #This file is LIVE reloaded by rspamd. Any changes are EFFECTIVE IMMEDIATELY. dummy.com该映射文件会被 Rspamd 热加载,改动即时生效。
第三步:重启 Rspamd 容器
以 docker compose 部署为例:
docker compose up antispam --force-recreate -d第四步(可选):在 Rspamd WebUI 中验证符号
用管理员账号登录 Mailu 管理后台并进入 Antispam,即可访问 Rspamd WebUI。在Symbols标签页把 group 下拉框切到local_bl,即可看到新增的规则。需要注意:只有在符号未配置 pre-filter(即没有action=行)时,该符号才会显示在 Symbols 页面;在该页面所做的改动不会保存回配置文件。
第五步:验证映射文件
在 Rspamd WebUI 的configuration页面中,可以看到路径为/overrides/blacklist.inc的映射及其描述 "Senders domain part is on the local blacklist"。
点击该映射可在 GUI 中实时编辑。请注意:只有对/overrides目录内映射的修改是持久的——通过 GUI 交互式做的修改在 Rspamd 容器重建后会被还原;无论通过 GUI 还是文件系统修改,所有改动都会立即生效。
六、自定义"可执行附件"黑名单
Mailu 会拒收它认为"可执行"或存在危险的附件。如果你希望调整这份扩展名黑名单,可以执行:
docker compose exec antispam cat /etc/rspamd/local.d/forbidden_file_extension.map > overrides/rspamd/forbidden_file_extension.map docker compose restart antispam随后编辑overrides/rspamd/forbidden_file_extension.map,修改后需要重启 Rspamd 才能生效。
该机制对应的底层实现位于 core/rspamd/conf/multimap.conf:
FORBIDDEN_FILE_EXTENSION { type = "filename"; filter = "extension"; map = [ "/etc/rspamd/local.d/forbidden_file_extension.map", ]; prefilter = true; action = "reject"; symbol = "FORBIDDEN_FILE_EXTENSION"; description = "List of forbidden file extensions"; message = "Forbidden attachment extension"; }这是一个典型的预过滤器:命中即reject,不再进行后续处理。容器内默认的扩展名清单(core/rspamd/conf/forbidden_file_extension.map)覆盖了常见的可执行与脚本类型,包括ace、ade、apk、bat、bin、cab、cmd、com、cpl、dll、exe、hta、iso、jar、js、jse、lnk、msi、ps1、scr、sys、vb、vbe、vbs、wsf、xll等 68 个扩展名。注意:该 map 文件在 core/rspamd/start.py 中会被特殊处理——它从/conf/模板目录复制后不会被当作可被 override 文件替换的常规配置,而是保留默认值,这正是文档要求先cat导出再编辑的原因。
七、宏扫描误报:覆盖 composites.conf
如果 Mailu 被配置为扫描宏(默认开启,由环境变量SCAN_MACROS控制,见 docs/configuration.rst),它会使用 oletools 提供的轻量工具mraptor扫描含宏的文档。默认只拦截被判定为"潜在有害"的宏,但仍可能出现误报。如需改变默认行为,可覆盖 antispam 容器中的/etc/rspamd/local.d/composites.conf:
docker compose exec antispam cat /etc/rspamd/local.d/composites.conf > overrides/rspamd/composites.conf docker compose restart antispam编辑overrides/rspamd/composites.conf即可覆盖 Rspamd 中的 mraptor 配置,改动同样需要重启 Rspamd 生效。
该文件的默认内容(模板)位于 core/rspamd/conf/composites.conf,其中定义了两条基于 oletools 符号的复合规则:
OLETOOLS_MACRO_MRAPTOR:当 mraptor 判定宏同时具备可访问性(OLETOOLS_A)与写入(OLETOOLS_W)或执行(OLETOOLS_X)能力时触发,得分 20.0;OLETOOLS_MACRO_SUSPICIOUS:命中OLETOOLS_FLAG、OLETOOLS_VBASTOMP或OLETOOLS_A时触发,得分 20.0。
这两条规则与 core/rspamd/conf/force_actions.conf 中的OLETOOLS_DANGEROUS(action = reject,直接拒收含危险宏的邮件)以及ANTIVIRUS_FAILED(soft reject,在 ClamAV/oletools 尚未就绪时临时拒收)共同构成了宏与病毒层面的多层防护。另外,SCAN_MACROS为True时,模板中的这两条规则才会被渲染出来;为False时它们直接消失。
八、配套的病毒扫描与强制动作
虽然原文档聚焦于垃圾过滤,了解与之联动的病毒扫描有助于完整理解 antispam 容器行为。当ANTIVIRUS=clamav时,Rspamd 会通过 core/rspamd/conf/antivirus.conf 启用 ClamAV 扫描(scan_mime_parts = true,连接到ANTIVIRUS_ADDRESS:3310),命中时触发CLAM_VIRUS符号;ANTIVIRUS_ACTION(默认discard)控制病毒邮件的处理方式,设为reject时改为在 SMTP 对话中直接拒收(见 docs/configuration.rst)。force_actions.conf中的ANTIVIRUS_FLAGGED(reject)与ANTISPOOF_*系列规则则对病毒与伪造域名实施强制拒收,确保安全事件不被低分掩盖。
九、排障与 FAQ 要点速查
- 为什么邮件评分很高却没进 Junk?检查用户设置中的 spam filter tolerance(默认 80%):评分百分比必须大于容差才会被移入 Junk。也可在 core/admin/mailu/ui/templates/user/settings.html 对应的滑杆界面中确认当前值。
- 为什么自定义 multimap 符号在 WebUI 中看不到?配置了
action=(pre-filter)的符号不会出现在 Symbols 标签页中,这是设计行为。 - 为什么 GUI 中改的黑名单重启后丢失?只有
/overrides目录内的映射修改是持久的;GUI 交互修改在容器重建时会被还原。 - 改了 overrides 文件不生效?对
forbidden_file_extension.map与composites.conf的修改都需要重启 antispam 容器;而blacklist.inc映射会被 Rspamd 热加载,即时生效。 rspamc提示连接失败?确认命令在 dovecot 容器内执行、目标为antispam:11334(控制端口见 core/rspamd/conf/worker-controller.inc),且密码为mailu。
十、参考资料
- 本文主体来源:docs/antispam.rst
- 过滤容差环境变量:docs/configuration.rst(
DEFAULT_SPAM_THRESHOLD,默认 80) - 宏扫描开关:docs/configuration.rst(
SCAN_MACROS,默认 True) - 病毒处理方式:docs/configuration.rst(
ANTIVIRUS_ACTION,默认 discard) - overrides 通用约定:docs/faq.rst
- 核心实现:Sieve 模板 core/admin/mailu/internal/templates/default.sieve、Dovecot 配置 core/dovecot/conf/dovecot.conf、Rspamd 配置 core/rspamd/conf/multimap.conf、core/rspamd/conf/composites.conf、core/rspamd/conf/force_actions.conf、core/rspamd/conf/antivirus.conf
- 后端
- 通信
【免费下载链接】Mailu
Insular email distribution - mail server as Docker images
相关推荐
Docker-Mailserver反垃圾邮件实战:Rspamd与SpamAssassin深度配置
Docker Mailserver反垃圾邮件实战:Rspamd与SpamAssassin深度配置 想要搭建一个安全可靠的邮件服务器,却总是被垃圾邮件困扰?😩
后端通信云原生Maddy反垃圾邮件配置终极指南:DNSBL、Rspamd与Milter集成
Maddy反垃圾邮件配置终极指南:DNSBL、Rspamd与Milter集成 Maddy邮件服务器是一款功能强大的可组合一体化邮件服务器,它内置了完整的反垃圾邮
后端通信docker-mailserver 集成 Rspamd 反垃圾邮件全指南:架构、配置与最佳实践
docker mailserver 集成 Rspamd 反垃圾邮件全指南:架构、配置与最佳实践 导读 本文围绕 docker mailserver(DMS)对
后端通信云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考