我最近做出了运行自己的邮件服务器的可疑决定。目前,我正在外包发送声誉,因为有很多简单的方法可以以接近零的成本做到这一点,但我负责入站。
这一切都始于谷歌决定传统的免费“Google Apps for Your Domain”正在吸引客户远离他们的付费产品。我知道这即将到来并且基本上已经准备好了(除了谷歌照片),所以我开始尝试各种邮件提供商,但没有一个符合要求。事实证明,GMail 实际上是相当不错的收件箱提供商。我与其他提供商遇到的最大问题是垃圾邮件过滤。 FastMail 很不错,但是屏蔽了一些重要的邮件。 MXroute 阻止的太多和太少。我差点又回到谷歌(强烈反对说服他们放弃“个人使用”的决定)。然而,最后我决定运行我自己的邮件服务器不会那么糟糕。
更多关于该设置的信息将在以后的文章中介绍,但我想谈谈我多年来一直设想的一种有趣的垃圾邮件控制技术。虽然简单,但使用大多数提供商提供的过滤功能实现起来还不够简单。但是通过访问自定义的Rspamd规则,实现起来很容易。
Rspamd 实际上开箱即用的表现非常出色,这种额外的过滤可能是不必要的。但由于我多年来一直在考虑这个想法,我想把它付诸实践,看看它的效果如何。
这是一种特定于任务的电子邮件地址。例如,GMail 允许使用 + 进行子寻址。所以可以将me+github@example
提供给 GitHub,然后我可以轻松地组织我的 GitHub 消息。如果我为我创建的每个帐户都这样做,那么如果我开始收到垃圾邮件,我就会知道是谁卖了我的信息。
这样做的主要问题是使用+
进行子寻址非常普遍。所以很多工具和服务都会剥离它。这意味着除了最不复杂的垃圾邮件发送者之外的所有垃圾邮件发送者都能够“猜测”您的主要电子邮件,或者只是随机化+
之后的内容以绕过任何阻止。
一个常见的解决方案是成熟的电子邮件别名。这样你就有了z2y8r3w3n@example
并且不允许任何未知地址。现在垃圾邮件发送者无法猜测随机地址或剥离每个帐户的信息。对此有很多选择,例如Firefox Relay等第三方服务和电子邮件提供商的内置功能,例如FastMail 的 Masked Email 。这些服务很棒,但主要问题是您每次注册新服务时都需要去配置一个新地址。这通常不会太痛苦,但仍然需要大量点击。
我的解决方案是签名地址。这种方式生成电子邮件地址很容易。它可以通过浏览器扩展程序或网站完成,无需与任何服务对话,甚至无需让您的设备在线。当我在思考这个问题时,我在Hacker News上看到了blame.email 。所以我决定窃取他们的算法,这样我就可以利用他们的前端。
他们的算法非常简单。它使用了不幸的 MD5(这意味着您不能使用浏览器crypto.subtle.digest
API ),但这里的密码学并不重要。目标是阻止幼稚的自动化,而不是有动机的攻击者。一个CRC-32就足够了。
name = "github.com" salt = "Sup3r S3cre+" hash = md5 ( " $name + $salt " ) .hex[0:8] signed_address = " $name - $hash @example"
所以我离开了github.com-3ece8a38@example
。
然后我配置 Rspamd 来验证这些签名。
local rspamd_cryptobox_hash = require "rspamd_cryptobox_hash" local md5 = rspamd_cryptobox_hash . create_specific "md5" local known = { abuse = true , blog = true , spam = false , -- Others redacted ... -- Signed addresses that have been revoked. [ "spammer-a8bffde3" ] = false , }; rspamd_config . KEVINCOX_TO = { type = "prefilter" , callback = function ( task ) local to = task : get_principal_recipient () -- Get just the user part, drop subaddress and domain. local user = to : match "^[^+@]*" if not user then -- If we can't identify a recipient add some spam score and quit. task : insert_result ( true , "KEVINCOX_TO_MISSING" , 2 . 0 , user ) return end local k = known [ user ] if k == true then -- A regular non-signed address. task : insert_result ( true , "KEVINCOX_TO_KNOWN" , 0 . 0 , user ) elseif k == false then -- Blocked (signed or unsigned) addresses. -- TODO: Forward to a spam reporting service. task : set_pre_result ( "reject" , "Confirmed Spammer" ) elseif user : find "-" then -- If the username contains a `-` it must be signed. local name , hash = user : match "^(.*)-([^-]*)$" md5 : reset () md5 : update ( name .. "+" .. "Sup3r S3cre+" ) local expected = md5 : hex (): sub ( 0 , 8 ) if hash == expected then -- Signed addresses skip the spam filter. task : set_pre_result ( "accept" , "Signed address." ) else task : set_pre_result ( "reject" , "Invalid recipient." ) end else -- Not known and not signed. task : insert_result ( true , "KEVINCOX_TO_UNKNOWN" , 1 . 0 , user ) end end , }
理想情况下,您可以拒绝所有未签名的内容,但世界并不完美。
- 我想要一些长期有效的电子邮件地址给朋友。
- 这是一个旧域,所以我过去给出了各种地址,但我还没有准备好撤销。
随着时间的推移,我会收集更多的数据,我会慢慢收紧规则。现在,所有内容都被归入以下类别之一。
- 已知地址:允许,但需定期进行垃圾邮件检查。
- 被阻止的地址:拒绝并报告。
- 有效签名地址:允许,跳过垃圾邮件过滤器。
- 阻塞模式:拒绝。 (例如,我拒绝所有包含
-
或.
的地址,因为我过去发出的电子邮件都没有使用这些字符。任何这些例子都是猜测的地址。) - 其他:允许(暂时),但会增加垃圾邮件检查。
我的设置使用了一个包罗万象的域,但可以对其进行简单的修改以使用子寻址。只需使用诸如me+$name-$hash@example
之类的格式。当然,拒绝仅发送给me@example
的邮件将更有价值,因为剥离细节很常见。
结论
这个解决方案是否过度设计?几乎肯定。您无需签名即可获得大部分收益。只需发送github@example
之类的电子邮件,99% 的公司都不会尝试猜测其他电子邮件地址。如果一个地址被出售,封锁该地址可能就足够了。这使您可以了解谁共享了您的电子邮件,并且可以毫不费力地进行适当的阻止。
然而,这个系统足够可靠,可以跳过垃圾邮件过滤器这一事实也是非常有益的。我不再需要担心垃圾文件夹中丢失的重要邮件,因为这些签名地址确保我从这些特权发件人那里获得一切(直到我撤销他们的特权)。
该系统的另一个小好处是它减少了垃圾邮件过滤器的负载。我试图摆脱一台非常便宜的服务器,而 1GiB 的 RAM 对于我在其上运行的东西来说很紧张。垃圾邮件过滤因缓慢的网络请求和冷磁盘缓存而变慢,并且经常需要 20-60 秒。签名地址会跳过 99% 的垃圾邮件过滤器,并且始终需要不到一秒钟的时间。这意味着邮件出现在我的收件箱中的速度明显更快,这是一个很好的改进。