编程 Rspamd 日志里的 [12.30/15.00] 不是判决:score 只给阈值,action 由模块定

2026-11-06 00:03:47

Rspamd 的 score 与 action 不是一回事:日志里的 [12.30/15.00] 该怎么读

现象

常见的两类误读:

  • 把日志里的 [12.30/15.00] 当成“离拒收还差 2.7 分”,拿来做监控和告警。
  • 看到 score 100500 却没拒信,就以为配置坏了。

Rspamd 在 FAQ 里写得很明确:score 是内部量,外部服务不应依赖 score;MTA 侧只看 action。官方原话大意是:永远用 action,score 只用于定义通用阈值和调试;score、action 阈值、真实 action 三者没有任何保证一致。

阈值文件与默认值

发行版自带 conf/actions.conf,不要直接改,升级会被覆盖:

actions {
  reject = 15;      # 达到此分拒收
  add_header = 6;   # 达到此分加头(标记为垃圾)
  greylist = 4;     # 达到此分做灰名单(发出 soft reject action)
  # unknown_weight = 1.0;
  # grow_factor = 1.1;
  # subject = "***SPAM*** %s"
}

文件末尾用 .include 合并 $LOCAL_CONFDIR/local.d/actions.conf(duplicate=merge,priority=1)与 override.d/actions.conf(priority=10,严格覆盖)。所以改配置写 local.d/actions.conf:local.d 是键级合并,override.d 是整段替换。

校验顺序:先 rspamadm configtest,再 systemctl reload rspamd(不是 restart)。

3.12.0 起 rspamadm configdump 增加 --non-default,只打印本地覆盖项,便于确认自己到底改了什么。

actions{} 键的真实含义

这是最容易误会的地方:段名叫 actions,实际是“score 阈值表”。

Rspamd 真正会返回的 action 是:

  • discard(收下但丢弃,仅特殊场景)
  • reject
  • rewrite subject
  • add header
  • no action
  • soft reject(1.9 起还有 quarantine)

actions{} 里没有 discard、没有 soft reject、没有 quarantine 的键;只有一个特殊的 greylist 键,它是给 greylisting 模块用的分数阈值。

也就是说:阈值决定“通用”行为,但模块可以绕过阈值直接指定 action。

forced action 列表与日志读法

能直接设定 action 的模块(官方列表):

  • greylist:需要灰名单时设 soft reject
  • ratelimit:触发限速时设 soft reject
  • dmarc:配置后可按发件域策略直接设定 action(默认不启用)
  • antivirus:规则里显式配置时可设 action
  • multimap:map 里写了 action 时生效
  • replies:配置后对回复邮件设 no action
  • force_actions:专门用来强制 action 的模块
  • spamtrap:可对 spamtrap 设 bypass
  • metadata_exporter:配置为无法上报时设 soft reject

日志里体现为 forced: 字段,且 score 会被改写成阈值量级:

...(default: T (reject): [100500.00/15.00] [...])... forced: reject "test"; score=100500.00 (set by bla)

读法:先看 forced:,再看括号里的 (reject) 和 [score/threshold]。

soft reject 与 reject 的区别

soft reject = 让 MTA 返回临时错误(4xx),真实邮件服务器会重试,垃圾机器人通常不会。所以灰名单、限速用 soft reject,而不是 reject。reject 是最终拒收。

“用户说发信被延迟几分钟才到”和“被拒收”是两条完全不同的链路,排查入口不同:前者看 greylist/ratelimit 模块,后者看 reject 阈值与 RBL、SPF 等符号权重。

早停:同一封信两次扫描分数不同

一旦达到 reject 分数,Rspamd 会停止后续检查以节省资源,但在到达阈值之前已经发出的网络检查(DNS/RBL 等)仍会跑完并回填。于是同一封邮件可能得到不同分数,但都 ≥ reject 阈值。

要拿到完整结果:请求时带 HTTP 头 Pass: all,rspamc 客户端对应 -p 参数。

自定义 action 的写法与坑

actions {
  # 只给阈值
  my_action = { score = 9.0; },
  # 只强制、不参与阈值
  phishing = { flags = ["no_threshold"]; },
}

限制:一封邮件最终只应用一个 action,所以定义两个同阈值 action 没有意义。

相关全局属性:

  • grow_factor:后续符号的权重乘数,默认 1.0(不放大);score = score + grow_factor * weight,grow_factor = grow_factor * grow_factor;负分不影响该值。
  • subject:rewrite subject 时替换主题的模板,%s 原主题,%d 分数。
  • unknown_weight:给未在任何地方注册权重的符号兜底;不设则未注册符号被静默忽略;设了意味着所有规则都会被检查。

可执行的排查/调优顺序

  1. 确认改动生效:写 local.d/,rspamadm configtest,rspamadm configdump --non-default,reload。
  2. 单封定位:rspamc 扫一遍原信,看 action、forced:、参与符号与权重。
  3. 监控口径:统计 action 分布(no action / add header / soft reject / reject),而不是 score 均值或分位数。score 不可比。
  4. 阈值是钝器:动 add_header/reject 是全局平移,只适合整体标定偏了;单个发件人误判应该改符号权重、multimap 白名单或 bayes 训练。

举例:mailcow 文档给的是全局 reject=15、add_header=8、greylist=7;nixos-mailserver 文档给的是关闭拒收 actions { reject = null; add_header = 6; greylist = 4; }(reject 默认 15)。这些数值来自各自发行配置,说明“默认可改”,不能当统一推荐值。

项目信息

  • 仓库:https://github.com/rspamd/rspamd
  • 默认 actions 配置:https://github.com/rspamd/rspamd/blob/master/conf/actions.conf
  • Metrics/action 文档:https://rspamd.com/doc/configuration/metrics.html
  • FAQ(scores 与 actions):https://rspamd.com/doc/faq.html

推荐文章

程序员茄子在线接单