一个针对垃圾邮件的计划
原文:A Plan for Spam
作者:Paul Graham 发表:2002-08
译者:Claude(baoyu-translate)
2002 年 8 月
(本文描述我们为练手 Arc 而构建的“防垃圾邮件 web 邮件客户端“中所用的过滤技术。改进后的算法见《更好的贝叶斯过滤》。)
我认为垃圾邮件是可以被阻止的,而办法是基于内容的过滤。发垃圾邮件者的阿喀琉斯之踵,是他们的消息本身。你架起的任何其他屏障他们都能绕过——至少到目前为止他们一直能。但他们必须把消息送到,无论那条消息是什么。如果我们能写出能识别这些消息的软件,他们就绕不过去。
对收件人来说,垃圾邮件很容易识别。如果你雇个人来读你的邮件、把垃圾邮件丢掉,他几乎不会有什么麻烦。那么,在不靠 AI 的前提下,要把这个过程自动化,得做到什么程度?
我认为我们能用相当简单的算法解决这个问题。事实上,我发现:仅仅把单个词的“垃圾邮件概率“按贝叶斯方式组合起来,就能把当今的垃圾邮件过滤得相当不错。我们用了一个稍作调整(下面会讲)的贝叶斯过滤器,目前每 1000 封垃圾邮件漏掉不到 5 封,且 0 个误报。
写垃圾邮件过滤器的人通常不会第一个想到统计方法。多数黑客的第一直觉是写软件去识别垃圾邮件的单个特征。你看着垃圾邮件想:这帮人胆儿真大——居然给我发以“亲爱的朋友“开头、或者主题行全大写、末尾跟着八个感叹号的邮件。这种东西我用一行代码就能过滤掉。
于是你真的去写了,开头也确实管用。几条简单规则就能砍掉收件箱里很大一块垃圾邮件。光是查“click“这个词,就能抓到我垃圾邮件语料里 79.7% 的邮件,误报只有 1.2%。
在尝试统计方法之前,我用大约六个月在写“识别单个垃圾邮件特征“的软件。我的发现是:抓到最后那几个百分点的垃圾邮件非常难——而且每当我把过滤器调得更紧,就有更多误报。
误报,是被错误地识别成垃圾邮件的正常邮件。对多数用户来说,漏掉一封正常邮件比收到一封垃圾邮件糟糕一个数量级——所以一个有误报的过滤器,就像一种**“治痘药却可能致命”**。
用户收到的垃圾邮件越多,他越不可能注意到垃圾邮件文件夹里那一封无辜的邮件。而且很奇怪——你的过滤器越好,误报反而越危险。因为当过滤器真的好的时候,用户更倾向于对它抓到的一切置之不理。
我不知道自己为什么这么久才肯试统计方法。我想是因为自己沉迷于亲手识别垃圾邮件特征这件事——好像在和发垃圾邮件者玩某种竞技游戏。(非黑客的人常常没意识到——多数黑客其实非常好胜。)当我真的试了统计分析之后,立刻发现它比我聪明得多。它当然发现“virtumundo“、“teens“是好的垃圾邮件指示词。但它也发现 “per”、“FL”、“ff0000” 是好的垃圾邮件指示词。事实上,“ff0000”(HTML 里的鲜红色)的指示力,和任何色情类词汇一样强。
下面我大致讲讲我是怎么做统计过滤的。我从一份垃圾邮件语料和一份非垃圾邮件语料开始——目前每份各约 4000 封。我扫描每一封邮件的全部文本——包括邮件头、嵌入的 HTML 和 JavaScript。当前我把字母数字字符、连字符、撇号、美元符号都视为 token 的一部分,其余视为 token 分隔符。(这里大概还有改进空间。)我忽略全是数字的 token,也忽略 HTML 注释——甚至不把它们当作 token 分隔符。
我数每个 token(目前忽略大小写)在每份语料里的出现次数。这一步结束时,我会得到两张大哈希表,每份语料一张,把 token 映射到出现次数。
接下来我建第三张哈希表——把每个 token 映射到“含有它的邮件是垃圾邮件的概率“。计算方法如下 [1]:
(let ((g (* 2 (or (gethash word good) 0)))
(b (or (gethash word bad) 0)))
(unless (< (+ g b) 5)
(max .01 (min .99 (float (/ (min 1 (/ b nbad))
(+ (min 1 (/ g ngood))
(min 1 (/ b nbad)))))))))
其中 word 是我们正在算概率的 token,good 和 bad 是第一步建的两张哈希表,ngood 和 nbad 分别是非垃圾邮件和垃圾邮件的封数。
我把它写成代码,是为了点出几个重要细节。我想让概率略微偏向“避免误报“,经过试错我发现一个好办法是:把 good 里的所有数字都乘以 2。这有助于把“在正常邮件里偶尔出现的词“和“几乎从不出现的词“区分开。我只考虑总共出现超过 5 次的词(实际上由于翻倍,在正常邮件里出现 3 次就够)。然后还有一个问题——对于“只在一种语料里出现“的词,赋多少概率?再次靠试错,我选了 0.01 和 0.99。这里也许有调优空间,但随着语料增长,这种调优会自动发生。
特别细心的人会注意到:我虽然把每份语料整体当作一长串文本来数 token 出现次数,但在算垃圾邮件概率时,我用的分母是“该语料里邮件的封数“,而不是文本总长。这又添了一点偏置,用来防误报。
新邮件到来时,它被切成 token;我取最“有意思“的 15 个 token——“有意思“由它们的垃圾邮件概率离中性的 0.5 有多远来衡量——用它们计算这封邮件是垃圾邮件的概率。如果 probs 是这 15 个单独概率组成的列表,组合概率这样算:
(let ((prod (apply #'* probs)))
(/ prod (+ prod (apply #'* (mapcar #'(lambda (x) (- 1 x)) probs)))))
实践中冒出的一个问题:对一个从没见过的词——也就是不在词概率哈希表里的词——该赋多少概率?再次靠试错,我发现 0.4 是个好数字。如果你从没见过某个词,它多半比较无辜——垃圾邮件的词反倒太眼熟了。
文末附录里有一些把这一算法应用到真实邮件上的例子。
如果上面的算法给一封邮件的概率超过 0.9,我就把它当作垃圾邮件。但实践中,把这条阈值放在哪里意义不大——因为很少有概率落在区间中段。
统计方法的一大优势是:你不必读那么多垃圾邮件。过去半年里我读了字面意义上几千封垃圾邮件,挺让人泄气的。Norbert Wiener(控制论之父)说过:和奴隶竞争,你也会变成奴隶。和发垃圾邮件者竞争,有种类似的让人贬值的感觉。要识别单个的垃圾邮件特征,你得钻进发垃圾邮件者的脑袋里——而老实说,我希望在那里面待的时间越短越好。
但贝叶斯方法真正的优势当然是:你知道自己在度量什么。SpamAssassin 这种基于特征识别的过滤器给邮件赋一个垃圾邮件“评分“,贝叶斯方法赋一个真正的概率。“评分“的问题是:没人知道它意味着什么。用户不知道,更糟的是——过滤器的开发者也不知道。一封邮件出现 “sex” 这个词应该得多少分?概率当然也可能错,但它的含义与“如何把证据组合起来“几乎没有任何含混。基于我的语料,“sex” 表示这封邮件是垃圾邮件的概率为 0.97,“sexy” 则为 0.99。而贝叶斯定理同样毫不含糊地告诉我们:在(不太可能的)没有任何其他证据的情况下,含这两个词的邮件是垃圾邮件的概率是 99.97%。
由于它度量的是概率,贝叶斯方法会综合考虑邮件里所有证据——好的和坏的。在垃圾邮件里反常地少出现的词(比如 “though”、“tonight”、“apparently”),对降低概率的贡献,和 “unsubscribe”、“opt-in” 这些坏词对升高概率的贡献一样大。所以一封其余完全无辜、只是恰好包含 “sex” 的邮件,不会被打上垃圾邮件标签。
理想情况下,概率当然应当按用户单独计算。我收到很多含 “Lisp” 这个词的邮件,而(迄今)没有一封含它的垃圾邮件。所以这种词对我来说,几乎就是一种通行密码。在我早期的过滤软件里,用户可以设一个这种词的列表,含它们的邮件会自动通过过滤。我列表里放了像 “Lisp” 这样的词,还放了我的邮编——这样在线购物的收据(其实听起来挺像垃圾邮件的)也能进来。我以为自己挺聪明,结果发现贝叶斯过滤器替我做了同样的事,而且还发现了一大堆我没想到的词。
我开头说我们的过滤器每 1000 封漏不到 5 封、0 个误报——这说的是用我自己的邮件构成的语料来过滤我自己的邮件。但这些数字并不误导,因为我提倡的正是这种做法:用每个用户自己收到的垃圾邮件和正常邮件去过滤他自己的邮件。本质上每个用户应当有两个删除按钮——普通删除,和“标记为垃圾邮件并删除“。后者的内容进垃圾邮件语料,其余进正常邮件语料。
你可以给用户初始一个“种子过滤器“,但归根到底每个用户应当根据他实际收到的邮件,拥有自己的“逐词概率“。这样:(a) 过滤器更有效;(b) 每个用户能自己决定“垃圾邮件“的精确定义;(c) 也许是最棒的一点——它让发垃圾邮件者很难调出能溜过过滤器的邮件。如果过滤器的“大脑“很大一部分在每个用户的个人数据库里,那“调出能溜过种子过滤器的邮件“对“能否溜过个体用户那些经过更多训练、彼此千差万别的过滤器“几乎不构成保证。
基于内容的过滤常常和白名单配合使用——白名单是一份“邮件可被无过滤接受“的发件人列表。建白名单的一个简单办法,是把“用户曾经发件去过的所有地址“维护成一份名单。如果邮件客户端有“标记为垃圾邮件“按钮,那么对所有“被普通删除(不是垃圾邮件)的邮件“,你也可以把其发件人地址加进白名单。
我支持白名单——但更多是为了省计算,而不是为了改善过滤。我曾经以为白名单会让过滤更容易,因为这样你只需过滤“陌生人“的邮件——而第一次给你写信的人,按惯例能跟你说什么是受限的。一个你已经认识的人可能给你发关于性的邮件;但第一次给你写信的人不太会。问题在于:人可以有不止一个邮箱地址——所以新的发件人地址不保证发件人是第一次给你写信。一位老朋友(尤其如果他是黑客)突然用一个新地址给你发邮件并不少见——所以你不能冒着误报的风险去特别严苛地过滤陌生人的邮件。
不过,从某种意义上说,我的过滤器本身就体现了一种白名单(和黑名单)——因为它们基于整封邮件,包括邮件头。所以在那个程度上,它们“知道“那些可信发件人的邮箱地址,甚至知道这些邮件从他们到我之间走的路由。它们对垃圾邮件也“知道“同样的东西——服务器名、邮件客户端版本号、协议等等。
如果我以为自己能保住当下的过滤率,那这个问题在我看来就解决了。但能过滤掉当下绝大多数垃圾邮件,意义不大——因为垃圾邮件会进化。事实上,到目前为止大多数反垃圾邮件技术,都像那种只会培育出一种新的、抗药菌株的杀虫剂。
我对贝叶斯过滤器更乐观——因为它和垃圾邮件一同进化。所以当发垃圾邮件者开始用 “c0ck” 替代 “cock” 来逃避基于单词的简单过滤器时,贝叶斯过滤器会自动注意到。事实上,“c0ck” 比 “cock” 是强得多的罪证——而贝叶斯过滤器精确地知道强多少。
不过,任何提出垃圾邮件过滤方案的人,都得能回答这个问题:如果发垃圾邮件者完全知道你在做什么,他们能多好地溜过你? 比如,我觉得如果“基于校验和的过滤“成为一道严肃障碍,发垃圾邮件者就会切换到“填空式技巧“(像 Mad Libs 词语填空游戏一样自动套模板)来生成正文。
要打败贝叶斯过滤器,“让邮件每封不同“或者“不再用单个的下流词“是不够的——他们必须让自己的邮件和你正常邮件无法区分。我觉得这会严重约束他们。垃圾邮件大多是销售话术——除非你的正常邮件全是销售话术,否则垃圾邮件不可避免地会有不同的特征。当然他们还得改(并且持续改)整个基础设施——否则不管他们对正文做什么,邮件头在贝叶斯过滤器看来还是一样的糟。我对发垃圾邮件者用的基础设施了解不够,没法说让邮件头看起来无辜有多难——但我猜那比让正文看起来无辜更难。
假设他们解决了邮件头的问题,“未来的垃圾邮件“大概会长成这样:“Hey there. Thought you should check out the following: http://www.27meg.com/foo”(“嘿。我觉得你应该看看下面这个:…”)——因为基于内容的过滤大概只能给发垃圾邮件者留下这点销售话术的空间。(其实让这都过去过滤器都难——因为邮件其余部分都中性的话,垃圾邮件概率就完全压在那个 URL 上,而要让 URL 看起来中性是要费一番功夫的。)
发垃圾邮件者从“运营所谓 opt-in 列表、连身份都不掩饰“的企业,到“劫持邮件服务器去推色情站点“的家伙都有。如果我们用过滤把他们的选项削减到上面那种邮件,那处在“合规“端的发垃圾邮件者基本会被挤出市场——他们因为各种州法律规定,必须在邮件里附上一段“为什么这不是垃圾邮件“和“如何取消订阅“的套话——这种文本极易识别。
(我以前以为“法律更严就能减少垃圾邮件“是天真的想法。现在我觉得:更严的法律也许不能减少发垃圾邮件者发出的总量,但确实能帮过滤器减少收件人实际看到的总量。)
整个谱系上看,只要你限制发垃圾邮件者能用的销售话术,你就不可避免地把他们挤出市场。“生意“这个词关键。发垃圾邮件者是生意人——他们发垃圾邮件是因为它管用。它管用,是因为虽然回应率低得令人发指(最好情况下每百万封 15 个回应,相比之下目录直邮是每百万封 3000 个),但对他们而言成本几乎是 0。对收件人这是巨大的成本——每百万收件人花一秒删一封邮件,加起来约 5 个工时;但发垃圾邮件者不必为之付钱。
不过,发垃圾邮件对发件人也确实有成本。 [2] 所以我们能把回应率压得越低——无论是靠过滤、还是靠用过滤器逼他们稀释销售话术——愿意靠这个营生的企业就越少。
发垃圾邮件者用现在这种销售话术,是为了抬高回应率。说到这里,比“钻进发垃圾邮件者的脑袋“更恶心的话——我们快速钻一下“回应了一封垃圾邮件的人“的脑袋。这种人要么轻信到惊人,要么对自己的性兴趣深度否认。无论哪种,垃圾邮件在我们看来再可憎或愚蠢,对他们都是令人兴奋的。如果这些话不令人兴奋,发垃圾邮件者也不会这样写。而 “Thought you should check out the following” 对垃圾邮件收件人的吸引力,远不及发垃圾邮件者今天写的那些东西。结果就是:如果它不能包含令人兴奋的销售话术,垃圾邮件作为营销渠道就变得不那么有效,愿意用它的企业也会变少。
那才是最终的大胜。我开始写垃圾邮件过滤软件,只是因为我不想再看那些东西了。但如果我们对过滤足够擅长,它就不再奏效——发垃圾邮件者就真的会停止发。
在所有对抗垃圾邮件的做法中——从软件到法律——我相信贝叶斯过滤会是单独最有效的那一种。但我也认为:我们采取的反垃圾邮件手段越多样越好——因为任何约束发垃圾邮件者的措施,都会让过滤更容易。哪怕在内容过滤这一域内,多种不同软件同时被使用我觉得也是好事。过滤器越多种多样,发垃圾邮件者就越难调出能同时溜过它们的邮件。
附录:过滤实例
下面这封是我写本文时正好到的一封垃圾邮件。它最“有意思“的 15 个词是:qvp0045 indira mx-05 intimail $7500 freeyankeedom cdo bluefoxmedia jpg unsecured platinum 3d0 qves 7c5 7c266675。这些词混合了邮件头和正文里的内容——这是垃圾邮件的典型情况。同样典型的是:在我数据库里这 15 个词里每一个的垃圾邮件概率都是 0.99。事实上概率为 0.99 的词远不止 15 个——这 15 个不过是先看到的。
不幸的是这让它成了一个使用贝叶斯定理的乏味例子。要看到一个有意思的概率“光谱“,得看下面这封其实相当非典型的垃圾邮件。
这封最“有意思“的 15 个词及其概率:madam 0.99 promotion 0.99 republic 0.99 shortest 0.047225013 mandatory 0.047225013 standardization 0.07347802 sorry 0.08221981 supported 0.09019077 people’s 0.09019077 enter 0.9075001 quality 0.8921298 organization 0.12454646 investment 0.8568143 very 0.14758544 valuable 0.82347786。这一次证据是好坏混合的。像 “shortest” 几乎和 “madam” 或 “promotion” 一样有力——只不过一个指证清白,一个指证有罪。但有罪的总和仍更强。按贝叶斯定理把这些数字组合起来,结果概率是 0.9027。
“Madam” 显然来自那种 “Dear Sir or Madam”(“尊敬的先生/女士”)开头的垃圾邮件。这种邮件并不常见,但 “madam” 在我正常邮件里从不出现——一切都看比例。
“Republic” 得分高,因为它常出现在尼日利亚式诈骗邮件里,也在涉及韩国和南非的垃圾邮件里出现过一两次。你可能会说这只是个意外——它恰巧帮我们识别这封垃圾邮件。但我研究垃圾邮件概率时发现:这种意外特别多——而且它们有种诡异的倾向,把事情推向正确的方向,而不是错误的方向。这一例里,“Republic” 出现在尼日利亚式诈骗邮件和这封邮件里,并不完全是巧合。有一整类涉及不发达国家的可疑商业提议——而那些国家的国名更可能显式地标注(正因为它们其实不是)“republic(共和国)”。[3]
另一方面,“enter” 是一个真正的误。它通常出现在退订指引里,但这封里被用得完全无辜。所幸统计方法相当稳健——可以容忍相当多的“误“,结果才会被带偏。
作为对照,下面是罕见鸟——一封溜过了过滤器的垃圾邮件。为什么?因为纯粹的运气——它正好塞满了在我真实邮件里常出现的词:perl 0.01 python 0.01 tcl 0.01 scripting 0.01 morris 0.01 graham 0.01491078 guarantee 0.9762507 cgi 0.9734398 paul 0.027040077 quite 0.030676773 pop3 0.042199217 various 0.06080265 prices 0.9359873 managed 0.06451222 difficult 0.071706355。这里有几个好消息。第一,这封邮件多半溜不过那些不专门搞编程语言、且没有一位叫 Morris 的好朋友的人的过滤器。对一般用户来说,这里前五个词都是中性的,对垃圾邮件概率没有贡献。
第二,我觉得基于词对的过滤(见下文)大概能抓到它:“cost effective”、“setup fee”、“money back”——挺有罪证味道的。当然如果它继续骚扰我(或我所在的网络),“Hostex” 本身就会被识别成垃圾邮件词。
最后,下面是一封无辜的邮件。它最“有意思“的 15 个词如下:continuation 0.01 describe 0.01 continuations 0.01 example 0.033600237 programming 0.05214485 i’m 0.055427782 examples 0.07972858 color 0.9189189 localhost 0.09883721 hi 0.116539136 california 0.84421706 same 0.15981844 spot 0.1654587 us-ascii 0.16804294 what 0.19212411。这里大多数词都说明这是无辜邮件。有两个味道不好的词——“color”(发垃圾邮件者爱用彩色字体)和 “California”(在用户证言和表单菜单里都会出现)——但它们的力度还盖不过 “continuation” 和 “example” 这种明显无辜的词。
有意思的是 “describe” 评分如此彻底无辜——它在我那 4000 封垃圾邮件里一次都没出现过。数据原来满是这种惊喜。分析垃圾邮件文本能让你学到的一件事是:发垃圾邮件者在多么狭窄的语言子集里活动。正是这件事,再加上每个用户邮件里同样有特征性的词汇库,才让贝叶斯过滤成为一个值得下注的方向。
附录:更多想法
一个我还没试过的想法是:基于词对——甚至三元词组——过滤,而不是基于单个词。这应该能给出更锐的概率估计。比如在我当前数据库里 “offers” 的概率是 0.96。如果你把概率建在词对上,你大概会得到 “special offers” 和 “valuable offers” 的概率约 0.99,而 “approach offers”(比如 “this approach offers”)的概率约 0.1 甚至更低。
我没这么做,原因是基于单个词的过滤已经管用得很。不过这意味着——一旦垃圾邮件变得更难检测,过滤器还有“收紧的余地“。(有意思的是,基于词对的过滤器实际上等同于一个反方向运行的马尔可夫链文本生成器。)
具体的“垃圾邮件特征“(比如收件人地址不在 To: 字段里)当然在识别中有价值。它们可以以“虚拟词“的形式纳入这套算法。我未来版本里大概会这样做——至少为最显眼的几个垃圾邮件指标。基于特征识别的过滤器在许多细节上是对的——它们缺的是把证据组合起来的整体纪律。
识别非垃圾邮件特征也许比识别垃圾邮件特征更重要。误报让人这么担心——以至于值得动用非常手段。我未来版本里大概会加一层专门为避免误报而设的二级测试——如果一封邮件触发了这一层,即使它的垃圾邮件概率高于阈值,也会被放行。
我不指望这一层是贝叶斯的。它不可避免地不仅是 ad hoc(临时的、就事论事的)的,而且基于猜测——因为误报的数量通常不会大到足以看出规律。(无论如何,备用系统不依赖和主系统同样的技术,这本来也是好事。)
未来我可能尝试的另一件事,是把额外注意力集中到邮件的某些特定部位。比如,当下大约 95% 的垃圾邮件都包含一个“想让你访问的站点“的 URL。(剩下的 5% 想让你打电话、回邮件给某个邮箱或美国邮政地址,少数情况下让你买某只股票。)在这些情况下,URL 几乎单独就足以判定邮件是不是垃圾邮件。
域名和(非德语)邮件正文里的其他文本不一样的地方在于:它们经常是把好几个词粘到一起的。在通用情况下计算开销很大,但试着把它们拆开也许值。如果一个过滤器从没见过 “xxxporn” 这个 token,它的单词垃圾邮件概率会是 0.4;而 “xxx” 和 “porn” 单独的概率(在我的语料里)分别是 0.9889 和 0.99,组合概率为 0.9998。
我预计随着发垃圾邮件者被逐步逼到正文里不再用罪证性词汇时,“分解域名“会越来越重要。(带 IP 地址的 URL 当然是极强的罪证——除了少数系统管理员的邮件之外。)
也许应该建一个“由发垃圾邮件者推广的 URL“的协作维护列表。我们需要 Raph Levien 研究的那种“信任度量“来防恶意或不专业的提交——但有了它会给任何过滤软件助一把力。它也会是抵制行动的一个方便基准。
测试可疑 URL 的另一个办法,是在用户看到提到它的邮件之前,派一个爬虫去看那个站点。你可以用一个贝叶斯过滤器给那个站点打分——就像给一封邮件打分一样——把站点上找到的东西纳入“邮件是垃圾邮件的概率“的计算。带重定向的 URL 当然格外可疑。
一个我觉得真的会很好的协作项目,是积累一份巨大的垃圾邮件语料库。一个庞大、干净的语料库是让贝叶斯过滤工作良好的关键。贝叶斯过滤器实际上就能直接用这个语料库作为输入。但这种语料库对别的种类的过滤器也很有用——因为可以用它来测试它们。
建立这种语料库面临一些技术问题。我们当然需要信任度量来防恶意/不专业的提交。我们还需要从邮件里抹掉个人信息(不只是 To 地址和抄送,还有比如退订 URL 的查询参数——它们经常把 To 地址编进去)。如果有人愿意挑这个项目,那对世界是件好事。
附录:定义垃圾邮件
我觉得对“什么是垃圾邮件“已经有大致共识,但有一个显式的定义会很有用。如果我们想建立一个垃圾邮件的中心语料库、甚至只是想有意义地比较各家的过滤率,我们就需要这件事。
首先,垃圾邮件不等于“未经请求的商业邮件“。如果我邻居听说我在找一辆状况好的旧 Raleigh 三速自行车(英国 Raleigh 牌自行车),给我发邮件说他可以卖一辆给我,我会很高兴;这封邮件既商业又未经请求。垃圾邮件的定义性特征(事实上它的 raison d’être(法语:存在意义))不是它未经请求,而是它自动化。
它通常是商业的,也只是顺带的一件事。如果有人开始群发邮件去支持某项政治事业,那它和推色情站的邮件一样是垃圾邮件。
我建议把垃圾邮件定义为未经请求的自动化邮件。这个定义因此包括了一些许多法律定义里不算的邮件。法律对垃圾邮件的定义——大概受了游说者的影响——倾向于把“和收件人有’已存关系’的公司发的邮件“排除在外。但比如说,从一家公司买东西并不意味着你请求了从他们那儿持续收到邮件。如果我从一家网店下了单,他们就开始给我连绵不绝地发邮件,那仍然是垃圾邮件。
发垃圾邮件的公司常常给你提供“unsubscribe(退订)“的方式,或者让你去他们站点改“账户偏好“以停止收邮件。这不足以让那种邮件不算垃圾邮件。“没有 opt-out“和“opt-in“不是一回事。除非收件人显式勾选了一个清晰标注(默认未选)的复选框、表示愿意接收,否则它就是垃圾邮件。
在某些业务关系里你确实隐式地请求了某些种类的邮件。在线下单时,我觉得你隐式请求了一封收据、以及在订单发货时的通知。Verisign(美国域名注册商)发邮件提醒我某个域名快到期了,我不介意(至少在他们就是该域名的实际注册商时)。但当 Verisign 给我发邮件,说有一份FREE Guide to Building My E-Commerce Web Site(免费的电商网站搭建指南)——那就是垃圾邮件。
注释
[1] 本文里的代码示例被翻译成了 Common Lisp——信不信由你,是为了更高的可读性。这里描述的应用,是我们写来测试一种叫 Arc 的、尚未发布的 Lisp 新方言用的。
[2] 当下最低的费率似乎是 200 美元发 100 万封垃圾邮件——非常便宜,每封 1/50 美分。但比如说过滤掉 95% 的垃圾邮件,会让发垃圾邮件者触达同一受众的成本翻 20 倍。能吃下这个倍数的利润空间的人,并不多。
[3] 一条经验法则——一个国家名字前的限定词越多,统治者越腐败。一个叫 The Socialist People’s Democratic Republic of X(X 社会主义人民民主共和国)的国家,多半就是世界上最不该住的地方。
致谢 Sarah Harlin 通读初稿;Daniel Giffin(同时也在写 Arc 的生产解释器)贡献了关于过滤的若干好想法、并搭起了我们的邮件基础设施;Robert Morris、Trevor Blackwell、Erann Gat 在垃圾邮件议题上做了许多讨论;Raph Levien 对信任度量给了建议;Chip Coldwell 和 Sam Steingold 对统计学给了建议。
本文与另外 14 篇文章一同收录于 《黑客与画家》。