在 2015 年 和 2016 年,我将“最佳拍档”奖授予了两个开源命令或程序类型,它们结合在一起,使我的世界变得更美好。今年,“最佳拍档”奖已转变为“最佳三人组”,因为为了解决我着手解决的问题——有效的服务器端电子邮件排序——需要三个软件协同工作。以下是我如何使用 SpamAssassin、MIMEDefang 和 Procmail 这三个常见且免费提供的开源软件包使一切正常工作。
问题
为了更轻松地管理我的电子邮件,我喜欢将收到的邮件分类到几个文件夹中(除了收件箱)。垃圾邮件总是被归档到垃圾邮件文件夹中,我每隔几天查看一次,以防万一我想要的邮件被标记为垃圾邮件。我还将来自其他几个来源的电子邮件分类到特定的文件夹中。其他所有内容默认归档到收件箱。
首先简单介绍一下术语:排序是对电子邮件进行分类并将其存储到适当文件夹中的过程。像 SpamAssassin 这样的过滤器对电子邮件进行分类。MIMEDefang 使用该分类通过在主题行中添加文本字符串来将邮件标记为垃圾邮件。该分类允许其他软件将电子邮件归档到指定的文件夹中。我一直在使用这两个应用程序,并且我需要软件来完成最后一步——即进行归档的软件。
我在 Thunderbird 中设置了几个电子邮件过滤器,Thunderbird 是我为个人需求找到的最佳客户端。我和我的妻子都在我们的电脑上使用电子邮件过滤器。当我们旅行或使用手持设备时,这些过滤器并不总是有效,因为 Thunderbird——或任何其他带有过滤器的电子邮件客户端——必须在我家里的电脑上运行才能执行过滤任务。我可以在我的笔记本电脑上设置过滤器,以便在旅行时对电子邮件进行排序,但这意味着我必须维护多组过滤器。
还有一个我想解决的技术问题。客户端电子邮件过滤依赖于在邮件被存入收件箱后扫描邮件。由于某些未知原因,有时客户端不会从收件箱中删除(清除)已移动的邮件。这可能是 Thunderbird 的问题(或者可能是我的 Thunderbird 配置问题)。我已经为此问题工作多年,但没有成功,即使经过多次完全重新安装 Fedora 和 Thunderbird 也是如此。
此外,垃圾邮件对我来说是一个主要问题。我有自己的电子邮件服务器,并且使用多个电子邮件地址。我已经拥有其中一些电子邮件帐户几十年了,它们已成为主要的垃圾邮件磁铁。事实上,我每天通常收到 1,200 到 1,500 封垃圾邮件——我的记录是一天内超过 2,500 封垃圾邮件——而且数量还在不断增加。
为了解决我的问题,我需要一种基于服务器而不是客户端的电子邮件归档方法(即,将邮件排序到适当的文件夹中)。这将解决几个问题:我不需要让电子邮件客户端在我的家庭工作站上运行才能执行过滤。我无需从我们的收件箱中删除或清除邮件——尤其是垃圾邮件。而且我无需在多个位置配置过滤器——我只需要在一个位置,即服务器上配置它们。
我的电子邮件服务器
大约在 1997 年,当我从 OS/2 切换到 Red Hat Linux 5 时,我选择了 Sendmail 作为我的电子邮件服务器,因为我已经工作了几年。从那时起,它一直是我的 邮件传输代理 (MTA),用于商业和个人用途。(我不知道为什么 Wikipedia 将 MTA 称为“消息”传输代理,而我所有其他参考资料都说是“邮件”传输代理。Wikipedia 页面的“讨论”选项卡对此进行了一些讨论,这让我更加困惑。)
我一直在使用 SpamAssassin 和 MIMEDefang 一起对收到的电子邮件进行评分和标记为垃圾邮件,并在主题中放置一个已知的字符串 ###SPAM###,以便我可以识别和排序垃圾邮件,无论是作为人类还是使用软件。我使用 UW IMAP 用于客户端访问电子邮件,但这在服务器端过滤和排序中不是一个因素。
是的,我为电子邮件的服务器端使用了很多老式的软件,但它们是众所周知的,运行良好,并且我了解如何让它们完成我需要它们完成的事情。
项目要求
我相信在开始一个项目之前,拥有一组明确定义的要求是必要的。根据我对问题的描述,我为这个项目创建了五个简单的要求
- 使用已添加到主题行中的识别文本,在服务器端将收到的垃圾邮件排序到垃圾邮件文件夹中。
- 将其他收到的电子邮件排序到指定的文件夹中。
- 避免已移动邮件未从收件箱中删除或清除的问题。
- 保留现有的 SpamAssassin 和 MIMEDefang 软件。
- 确保任何新软件都易于安装和配置。
这组目标意味着我需要一个与我已经拥有的部件良好集成的排序程序。
Procmail
经过广泛的研究,我选择了历史悠久的 Procmail。我知道——更多老东西——而且现在也几乎不受支持了。但它可以完成我需要它完成的事情,并且已知可以与我已经使用的软件良好地协同工作。它很稳定,没有已知的严重错误。它可以配置为在系统级别以及个人用户级别使用。
Red Hat 和基于 Red Hat 的发行版,例如 CentOS 和 Fedora,使用 Procmail 作为 SendMail 的默认 邮件投递代理 (MDA),因此甚至不需要安装;它已经存在了。我的服务器运行 CentOS,因此使用 Procmail 真是轻而易举。
除了投递电子邮件外,Procmail 还可以用于过滤和排序电子邮件。Procmail 规则(称为配方)可用于识别垃圾邮件并将其删除或排序到指定的邮件文件夹中。其他配方也可以识别和排序其他邮件。Procmail 可用于许多其他用途,除了将电子邮件排序到指定的文件夹中,例如自动转发、复制等等。这些其他任务超出了本文的范围,但理解排序应该让你更好地理解如何完成这些其他任务。
它是如何工作的
将 SpamAssassin、MIMEDefang 和 Procmail 结合在一起用于反垃圾邮件解决方案的方法有很多,因此我不会深入探讨如何配置它们。相反,我将重点介绍如何集成这三个软件包来实现我自己的解决方案。
收到的电子邮件处理从 SendMail 开始。我将这一行添加到我的 sendmail.mc 配置文件中
INPUT_MAIL_FILTER(`mimedefang', `S=unix:/var/spool/MIMEDefang/mimedefang.sock, T=S:5m;R:5m')dnl
此行调用 MIMEDefang 作为电子邮件处理的一部分。请务必在对 SendMail 进行任何配置更改后运行 make 命令,然后重新启动 SendMail。(有关更多信息,请参阅 SpamAssassin:集成和配置实用指南 的第 8 章。)
SpamAssassin 可以在某些应用程序中作为独立软件运行;但是,在这种环境中,它不作为守护程序运行,而是由 MIMEDefang 调用,并且每封电子邮件首先由 SpamAssassin 处理以生成其垃圾邮件评分。
SpamAssassin 提供了一组默认规则,但你可以修改现有规则的分数、添加自己的规则以及通过修改 /etc/mail/spamassassin/local.cf 文件来创建白名单和黑名单。该文件可能会变得非常大;我的文件刚刚超过 70KB,并且仍在增长。
SpamAssassin 使用默认和自定义规则集和分数来为每封电子邮件生成总分。MIMEDefang 使用 SpamAssassin 作为子例程,并将垃圾邮件分数作为返回代码接收。
MIMEDefang 用 Perl 编写,因此很容易破解。我破解了 /etc/mail/mimedefang-filter 中代码的最后主要部分,以提供比默认值更精细的过滤细分。以下是代码的这一部分在我的安装中的外观(我对代码的这一部分进行了重大更改,因此你的代码可能看起来与此大相径庭)
#####################################################################
# Determine how to handle the email based on its spam score and #
# add an appropriate X-Spam-Status header and alter the subject. #
#####################################################################
# Set required_hits in sa-mimedefang.cf to get value for $req #
#####################################################################
if ($hits >= $req) {
action_add_header("X-Spam-Status", "Spam, score=$hits required=$req tests=$names");
action_change_header("Subject", "####SPAM#### ($hits) $Subject");
action_add_part($entity, "text/plain", "-suggest", "$report\n", "SpamAssassinReport.txt", "inline");
# action_discard();
} elsif ($hits >= 8) {
action_add_header("X-Spam-Status", "Probably, score=$hits required=$req tests=$names");
action_change_header("Subject", "####Probably SPAM#### ($hits) $Subject");
action_add_part($entity, "text/plain", "-suggest", "$report\n", "SpamAssassinReport.txt", "inline");
} elsif ($hits >= 5) {
action_add_header("X-Spam-Status", "Possibly, score=$hits required=$req tests=$names");
action_change_header("Subject", "####Possibly SPAM#### ($hits) $Subject");
action_add_part($entity, "text/plain", "-suggest", "$report\n", "SpamAssassinReport.txt", "inline");
} elsif ($hits >= 0.00) {
action_add_header("X-Spam-Status", "Probably not, score=$hits required=$req tests=$names");
# action_add_part($entity, "text/plain", "-suggest", "$report\n", "SpamAssassinReport.txt", "inline");
} else {
# If score (hits) is less than or equal to 0
action_add_header("X-Spam-Status", "No, score=$hits required=$req tests=$names");
# action_add_part($entity, "text/plain", "-suggest", "$report\n", "SpamAssassinReport.txt", "inline");
}
以下是代码中更改电子邮件主题行的行
action_change_header("Subject", "####SPAM#### ($hits) $Subject");
实际上,它调用另一个 Perl 子例程来使用我要添加的字符串作为参数来更改主题行,但效果是相同的。主题行现在包含字符串 ####SPAM#### 和垃圾邮件评分(即变量 $hits)。在主题行中包含此已知字符串使进一步过滤变得容易。
修改后的电子邮件返回给 SendMail 以进行进一步处理,SendMail 调用 Procmail 作为 MDA。
Procmail 使用全局和用户级配置文件,但必须创建全局 /etc/procmailrc 文件和个人用户 ~/.procmailrc 文件。文件的结构相同,但全局文件对所有收到的电子邮件进行操作,而本地文件可以为每个个人用户配置。由于我不使用全局文件,因此所有排序都在用户级别完成。我的 .procmailrc 文件很简单
# .procmailrc file for david@both.org
# Rules are run sequentially - first match wins
PATH=/usr/sbin:/usr/bin
MAILDIR=$HOME/mail #location of your mailboxes
DEFAULT=/var/spool/mail/david
# Send Spam to the spam mailbox
# This is my new style SPAM subject
:0
* ^Subject:.*####SPAM####
$HOME/spam
# Political stuff goes here. Must be using my political email address
:0
* ^To:.*political
$HOME/Political
# SysAdmin stuff goes here. Usually system log messages
:0
* ^Subject:.*(Logwatch|rkhunter|Anacron|Cron|Fail2Ban)
$HOME/AdminStuff
# drops messages into the default box
:0
* .*
请注意,.procmailrc 文件必须位于我的电子邮件帐户在电子邮件服务器上的主目录中,而不是我的工作站上的主目录中。由于大多数电子邮件帐户不是登录帐户,因此它们使用 nologin 程序作为默认 shell,因此管理员必须创建和维护这些文件。另一种选择是更改为登录 shell,例如 Bash,并设置密码,以便知识渊博的用户可以登录到他们在服务器上的电子邮件帐户并维护他们的 .procmailrc 文件。
每个 Procmail 配方都以第一行上的 :0(是的,那是零)开头,总共包含三行。第二行以 * 开头,并包含一个条件语句,该语句由 Procmail 与收到的电子邮件中每一行进行比较的正则表达式 (regex) 组成。如果存在匹配项,Procmail 会将电子邮件排序到第三行指定的文件夹中。在进行比较时,^ 符号表示行的开头。
我的 .procmailrc 文件中的第一个配方将 MIMEDefang 在主题行中识别的垃圾邮件排序到我的垃圾邮件文件夹中。第二个配方将政治电子邮件(通过我用于各种政治组织的志愿者工作的特殊电子邮件地址识别)排序到其自己的文件夹中。第三个配方将我从我处理的许多计算机收到的海量系统电子邮件排序到我的系统管理员职责的邮箱中。此设置使这些电子邮件非常容易找到。
请注意使用括号来括起要匹配的字符串列表。每个字符串都用竖线分隔,也称为管道 ( | ),它用作逻辑“或”。所以条件行
* ^Subject:.*(Logwatch|rkhunter|Anacron|Cron|Fail2Ban)
读作“如果主题行包含 Logwatch 或 rkhunter 或 ... 或 Fail2Ban。”由于 Procmail 忽略大小写,因此无需创建查找各种大小写组合的配方。
最后一个配方将所有不匹配其他配方的电子邮件放入默认文件夹,通常是收件箱。
在我的主目录中拥有 .procmailrc 文件不会导致 Procmail 过滤我的邮件。我必须添加另一个文件,即以下 ~/.forward 文件,它告诉 Procmail 过滤我的所有收到的电子邮件
# .forward file
# process all incoming mail through procmail - see .procmailrc for
# the filter rules.
|/usr/bin/procmail
创建或修改 Procmail 配置文件时,无需重新启动 SendMail 或 MIMEDefang。
有关 Procmail 配置和配方创建的更多详细信息,请参阅 SpamAssassin 书籍 和 RHEL 部署指南中的 Procmail 信息。
一些补充说明
请注意,MIMEDefang 必须在 SendMail 之前启动,以便它可以创建套接字,SendMail 在其中发送电子邮件进行处理。我有一个简短的脚本(自动化一切!),我用它来以正确的顺序停止和重新启动 SendMail 和 MIMEDefang,以便 local.cf 文件中的新规则或修改后的规则生效。
我的 SpamAssassin local.cf 文件中已经有大量的规则和分数修改器,因此,尽管我本可以使用 Procmail 本身进行垃圾邮件过滤和排序,但转换所有这些规则将需要大量工作。我还认为 SpamAssassin 在评分方面做得更好,因为它不依赖于单个规则来匹配,而是来自所有规则的聚合分数,以及来自贝叶斯过滤的分数。
当可以使用已知字符串(例如我已配置 MIMEDefang 放置在主题行中的字符串)非常明确地进行匹配时,Procmail 可以很好地工作。我认为 Procmail 作为垃圾邮件过滤过程中的最终排序阶段比作为完整的解决方案本身更好。也就是说,我知道许多管理员仅使用 Procmail 就完成了完整的垃圾邮件过滤解决方案。
现在我已经安装了服务器端过滤,我在选择电子邮件客户端方面受到一些限制,因为我不再需要执行过滤和排序的客户端。我也不需要让电子邮件客户端一直运行以执行过滤和排序。
关于 Procmail 消亡的报道被大大夸大了
在为本文进行研究时,我发现许多 Google 结果(日期从 2001 年到 2013 年)都宣称 Procmail 已死。证据包括损坏的网页、丢失的源代码以及 Wikipedia 上声明 Procmail 已死并链接到更新的替代品的句子。但是,所有 Red Hat、Fedora 和 CentOS 发行版都将 Procmail 安装为 SendMail 的 MDA。Red Hat、Fedora 和 CentOS 存储库都具有 Procmail 的源 RPM,并且源代码也在 GitHub 上。
考虑到 Red Hat 继续使用 Procmail,我使用这个成熟的软件没有任何问题,它可以默默无闻地完成它的工作。
资源
- SpamAssassin:配置、自定义和集成实用指南 也包含有关 MIMEDefang 和 Procmail 的信息
- Wikipedia 上的 SpamAssassin
- Wikipedia 上的 MIMEDefang
- Red Hat 的 Procmail 文档
- Procmail 常见问题解答
3 条评论