SMTP 服务器搭建完全指南 / 第 6 章:反垃圾邮件策略
第 6 章:反垃圾邮件策略
反垃圾邮件不是一道墙,而是多层防线的协同作战。
6.1 反垃圾邮件架构
6.1.1 多层防御体系
邮件到达
│
▼
┌───────────────────────┐
│ 第 1 层:连接级过滤 │ ← RBL、连接速率限制、灰名单
│ • 客户端 IP 黑名单 │
│ • PTR 记录检查 │
│ • 灰名单延迟 │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 第 2 层:信封级过滤 │ ← 发件人/收件人验证
│ • SPF 验证 │
│ • 发件人域名验证 │
│ • 收件人存在性验证 │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 第 3 层:内容级过滤 │ ← SpamAssassin、病毒扫描
│ • 垃圾邮件评分 │
│ • 病毒扫描(ClamAV) │
│ • 附件过滤 │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ 第 4 层:投递后处理 │ ← 用户反馈、学习
│ • 用户标记垃圾邮件 │
│ • Bayesian 学习 │
│ • 白名单管理 │
└───────────────────────┘
6.1.2 防御层次对比
| 层次 | 工具/技术 | 检查点 | 性能影响 | 误判率 |
|---|---|---|---|---|
| 连接级 | RBL、灰名单 | SMTP 连接阶段 | 低 | 低 |
| 信封级 | SPF、发件人验证 | MAIL FROM/RCPT TO | 低 | 极低 |
| 内容级 | SpamAssassin | 邮件正文 | 高 | 中 |
| 投递后 | Bayesian | 用户邮箱 | 无 | 低 |
6.2 RBL 黑名单检查
6.2.1 什么是 RBL
RBL(Real-time Blackhole List)是实时更新的 IP 黑名单数据库,记录了已知的垃圾邮件发送源。
6.2.2 常用 RBL 服务
| RBL 服务 | DNS 查询地址 | 说明 | 免费/付费 |
|---|---|---|---|
| Spamhaus ZEN | zen.spamhaus.org | 综合黑名单 | 免费查询 |
| SpamCop | bl.spamcop.net | 社区驱动 | 免费 |
| Barracuda | b.barracudacentral.org | 商业级 | 免费查询 |
| SpamRATS | all.spamrats.com | 综合 | 免费 |
| PSBL | psbl.surriel.com | 被动收集 | 免费 |
6.2.3 配置 Postfix 使用 RBL
# /etc/postfix/main.cf — RBL 检查配置
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unknown_sender_domain,
reject_unknown_reverse_client_hostname,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client bl.spamcop.net,
reject_rbl_client b.barracudacentral.org,
reject_rhsbl_reverse_client dbl.spamhaus.org,
reject_rhsbl_sender dbl.spamhaus.org,
permit
# RBL 拒绝信息自定义
smtpd_reject_footer = \nFor more info, visit https://example.com/mail-policy
6.2.4 RBL 配置参数
# 拒绝来自 RBL 的连接
reject_rbl_client zen.spamhaus.org
# 带白名单的 RBL 检查
check_client_access hash:/etc/postfix/rbl_whitelist,
reject_rbl_client zen.spamhaus.org
# 不同响应码的 RBL 检查
reject_rbl_client zen.spamhaus.org=127.0.0.2 # 仅拒绝 SBL
reject_rbl_client zen.spamhaus.org=127.0.0.4 # 仅拒绝 XBL
# /etc/postfix/rbl_whitelist — RBL 白名单
# 豁免特定 IP 的 RBL 检查
203.0.113.50 OK
10.0.0.0/8 OK
trusted.com OK
# 生成数据库
sudo postmap /etc/postfix/rbl_whitelist
6.3 灰名单(Greylisting)
6.3.1 灰名单原理
灰名单工作流程:
┌────────────────────────────────────────────────┐
│ 1. 首次收到邮件时,临时拒绝(4xx 错误码) │
│ 2. 合法的邮件服务器会在稍后重试 │
│ 3. 垃圾邮件发送器通常不会重试 │
│ 4. 重试的邮件被接受并记录到白名单 │
│ 5. 后续同三元组的邮件直接放行 │
└────────────────────────────────────────────────┘
三元组 = (客户端 IP, 发件人地址, 收件人地址)
6.3.2 安装 Postgrey
# 安装 Postgrey
sudo apt install -y postgrey
# 启动服务
sudo systemctl enable --now postgrey
# 检查服务状态
sudo systemctl status postgrey
6.3.3 配置 Postfix 使用灰名单
# /etc/postfix/main.cf
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service inet:127.0.0.1:10023, # Postgrey
reject_rbl_client zen.spamhaus.org,
permit
6.3.4 Postgrey 配置
# /etc/default/postgrey
# 启动参数
POSTGREY_OPTS="--inet=127.0.0.1:10023 --delay=300 --max-age=35"
# 参数说明:
# --inet: 监听地址和端口
# --delay: 首次拒绝后的等待秒数(默认 300)
# --max-age: 白名单记录保留天数(默认 35)
# --greylist-text: 自定义拒绝信息
6.3.5 灰名单白名单管理
# /etc/postgrey/whitelist_clients — 客户端 IP 白名单
# 豁免大型邮件服务(它们的重试机制可靠)
# 格式:IP 或域名正则
/^.*\.google\.com$/
/^.*\.microsoft\.com$/
/^.*\.amazonaws\.com$/
/^.*\.outlook\.com$/
# /etc/postgrey/whitelist_recipients — 收件人白名单
# 这些收件人的邮件不经过灰名单
[email protected]
[email protected]
# 重启 Postgrey 生效
sudo systemctl restart postgrey
6.4 SpamAssassin
6.4.1 安装 SpamAssassin
# 安装 SpamAssassin 和相关组件
sudo apt install -y spamassassin spamc
# 创建专用用户
sudo useradd -r -s /usr/sbin/nologin spamd
# 启动 SpamAssassin 守护进程
sudo systemctl enable --now spamassassin
# 检查服务状态
sudo systemctl status spamassassin
6.4.2 配置 Postfix 使用 SpamAssassin
# 方法 1:使用 Content Filter(推荐)
# /etc/postfix/main.cf
content_filter = spamassassin
# /etc/postfix/master.cf — 添加过滤器
spamassassin unix - n n - - pipe
user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
# 方法 2:使用 Amavis(集成反垃圾和防病毒)
sudo apt install -y amavisd-new
# /etc/postfix/main.cf
content_filter = smtp-amavis:[127.0.0.1]:10024
# /etc/postfix/master.cf
smtp-amavis unix - - n - - smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
6.4.3 SpamAssassin 规则配置
# /etc/spamassassin/local.cf — 本地配置
# 基础设置
required_score 5.0 # 垃圾邮件判定阈值
report_safe 0 # 0: 附件形式,1: 替换正文
use_bayes 1 # 启用 Bayesian 学习
bayes_auto_learn 1 # 自动学习
bayes_auto_learn_threshold_nonspam 0.1 # 非垃圾阈值
bayes_auto_learn_threshold_spam 7.0 # 垃圾阈值
# 白名单/黑名单
whitelist_from *@trusted.com
blacklist_from *@spam-domain.com
# 自定义规则
header LOCAL_SPAM_SUBJECT Subject =~ /免费.*中奖/
score LOCAL_SPAM_SUBJECT 5.0
body LOCAL_SPAM_BODY /点击这里领取奖金/
score LOCAL_SPAM_BODY 3.0
# DNS 检查
skip_rbl_checks 0
use_razor2 1 # 启用 Razor2
use_pyzor 1 # 启用 Pyzor
6.4.4 SpamAssassin 评分阈值
| 分数 | 含义 | 处理建议 |
|---|---|---|
| < 5.0 | 正常邮件 | 正常投递 |
| 5.0 - 10.0 | 可疑邮件 | 标记为垃圾邮件 |
| 10.0 - 15.0 | 高度可疑 | 隔离或拒绝 |
| > 15.0 | 几乎确定是垃圾 | 直接拒绝 |
6.4.5 更新 SpamAssassin 规则
# 手动更新规则
sudo sa-update
# 设置自动更新(cron)
sudo tee /etc/cron.d/spamassassin-update << 'EOF'
30 4 * * * root /usr/bin/sa-update && /usr/bin/systemctl reload spamassassin
EOF
# 检查规则版本
sa-update --lint
6.5 Postfix 内置过滤
6.5.1 发件人验证
# /etc/postfix/main.cf
# 拒绝发件人域名不存在
smtpd_sender_restrictions =
reject_unknown_sender_domain,
reject_non_fqdn_sender,
reject_sender_login_mismatch
# 拒绝发件人域名无 MX 记录
smtpd_sender_restrictions =
reject_unknown_sender_domain
# 限制发件人格式
smtpd_sender_restrictions =
reject_non_fqdn_sender
6.5.2 HELO/EHLO 验证
# 拒绝无效的 HELO/EHLO
smtpd_helo_restrictions =
permit_mynetworks,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
reject_unknown_helo_hostname
# 自定义 HELO 检查
smtpd_helo_restrictions =
permit_mynetworks,
check_helo_access hash:/etc/postfix/helo_access,
reject_invalid_helo_hostname
# /etc/postfix/helo_access
# 拒绝声称是这些域名的连接
example.com REJECT Don't pretend you are us
localhost REJECT Don't use localhost in HELO
6.5.3 header_checks(邮件头过滤)
# /etc/postfix/header_checks
# 拒绝包含特定主题的邮件
/^Subject:.*中奖.*免费/ REJECT Spam detected
# 删除特定邮件头
/^X-Mailer:.*SpammerTool/ IGNORE
# 标记可疑邮件
/^Subject:.*紧急.*回复/ HOLD Possible spam
# 在 main.cf 中启用
header_checks = regexp:/etc/postfix/header_checks
6.5.4 body_checks(邮件正文过滤)
# /etc/postfix/body_checks
# 拒绝包含特定内容的邮件
/点击这里领取奖金/ REJECT Spam content detected
/http:\/\/suspicious-link/ REJECT Suspicious link
# 在 main.cf 中启用
body_checks = regexp:/etc/postfix/body_checks
# ⚠️ 注意:body_checks 性能开销较大,谨慎使用
6.6 ClamAV 病毒扫描
6.6.1 安装 ClamAV
# 安装 ClamAV
sudo apt install -y clamav clamav-daemon clamav-freshclam
# 更新病毒库
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
# 启动 ClamAV 守护进程
sudo systemctl enable --now clamav-daemon
6.6.2 集成 Amavis + ClamAV + SpamAssassin
# Amavis 已集成 ClamAV 和 SpamAssassin
# /etc/amavis/conf.d/15-content_filter_mode
@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);
@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
# /etc/amavis/conf.d/50-user
use strict;
@local_domains_acl = ( "example.com" );
$sa_tag_level_deflt = -999; # 所有邮件都添加 SpamAssassin 标头
$sa_tag2_level_deflt = 5.0; # 标记为垃圾邮件的阈值
$sa_kill_level_deflt = 10.0; # 拒绝/隔离阈值
$sa_spam_subject_tag = '***SPAM*** ';
# ClamAV 设置
@av_scanners = (
['ClamAV-clamd',
\&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.ctl"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/],
);
6.7 综合反垃圾邮件配置
完整的 main.cf 反垃圾配置
# /etc/postfix/main.cf — 综合反垃圾邮件配置
# ==================== 连接级限制 ====================
smtpd_client_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_reverse_client_hostname,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client bl.spamcop.net
# ==================== HELO 限制 ====================
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname
# ==================== 发件人限制 ====================
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_sender_domain,
reject_non_fqdn_sender
# ==================== 收件人限制(含灰名单)====================
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unknown_recipient_domain,
reject_non_fqdn_recipient,
check_policy_service inet:127.0.0.1:10023,
reject_unverified_recipient,
permit
# ==================== 内容过滤 ====================
content_filter = smtp-amavis:[127.0.0.1]:10024
# ==================== 邮件头/正文检查 ====================
header_checks = regexp:/etc/postfix/header_checks
6.8 业务场景:企业反垃圾邮件策略
场景描述
一家金融企业需要严格的反垃圾邮件策略,要求:
- 误判率极低(不能漏掉重要邮件)
- 符合金融行业合规要求
- 支持审计和报告
配置方案
# 保守的反垃圾策略(低误判率)
# SpamAssassin 阈值调高
required_score 8.0
# 仅使用最可靠的 RBL
smtpd_client_restrictions =
permit_mynetworks,
reject_rbl_client zen.spamhaus.org=127.0.0.2 # 仅 SBL
# 隔离而非拒绝可疑邮件
# 使用 Amavis 隔离功能
$final_spam_destiny = D_DISCARD; # 隔离到隔离区
# 邮件审计日志
# 在 main.cf 中添加
always_bcc = [email protected]
6.9 注意事项
⚠️ 误判处理:
- 定期检查垃圾邮件隔离区
- 提供用户报告误判的渠道
- 使用
whitelist_from白名单重要发件人
⚠️ RBL 查询性能:
- 每次 RBL 查询都会产生 DNS 请求
- 建议使用本地 DNS 缓存(如
unbound)- 限制 RBL 查询数量(只使用最可靠的)
💡 灰名单的影响:
- 首次邮件投递会有 5-15 分钟延迟
- 向用户说明情况,避免投诉
- 白名单大型邮件服务(Gmail、Outlook)