规范化邮件地址的库(不仅仅是清理)

12

有多种方法可以生成电子邮件地址字符串,这些字符串在直接字符串比较时不同(见下文),但在逻辑上是等价的(即发送到两个地址的邮件将发送到同一个邮箱)。 这通常允许用户提供看似独特的电子邮件地址,即使严格相等被禁止。

我希望找到一个能够尝试规范化的库,以便在大量电子邮件地址集中查找一些重复项。目标是尽可能多地找到重复项。 考虑到这对于多种用途非常有用(在我的情况下,它是简单的滥用检测,因为滥用账户倾向于(尝试)重复使用某些账户),我认为可能已经存在解决方案。

那么有哪些内容会发生变化呢?我至少知道以下几点:

  • 域名部分不区分大小写(根据 DNS);但本地部分可能是大小写敏感的,这取决于邮件提供商(例如,Gmail认为它不区分大小写)
  • 许多域名具有别名(googlemail.com等同于gmail.com)
  • 某些电子邮件提供商允许其他它们忽略的变体(例如,Gmail忽略电子邮件地址中的任何点!)

理想情况下,这将在Java中实现,尽管脚本语言也可以(命令行工具)。


你正在使用哪种编程语言?请添加一个标签。 - Jesse Barnum
理想情况下使用Java,但脚本语言也可以(可以是脚本的一部分,不一定是服务)。 - StaxMan
我想到的是用Java编写的解析器(带有正则表达式)。这是你所想的吗? - zawhtut
那个容易做到(将域名转换为小写,删除或替换不需要的字符):但我真正寻找的是额外的规则 - 例如,应对Gmail有哪些邮件提供商别名等。一旦你拥有了这些,使用正则表达式库可以完成基本工作。因此,基本的清理很简单(并且被其他问题涵盖);我正在寻找更完整(深入)的标准化方法。 - StaxMan
2个回答

21

通过在Google上搜索"归一化邮箱地址",我能找到一些代码片段,但没有足够全面的。恐怕您需要编写自己的工具。如果我要编写这样的工具,我认为我会应用以下几条规则:

首先,该工具将将域名(@后面)转换为小写字母。除非您想处理带有国际域名的电子邮件,否则这不应该太难。例如,JoE@caFÉ.fR(请注意E上的重音符号),应首先经过Nameprep算法。这将导致JoE@xn--caf-dma.fr。我从未见过带有这种国际电子邮件地址的人,但我猜您可能会在中国或日本找到一些。

RFC 5322规定电子邮件的本地部分(@之前)区分大小写,但实际上几乎所有提供商的非正式标准是忽略大小写(我从未见过人类使用区分大小写的电子邮件地址,但我想仍有一些系统管理员在使用Unix电子邮件帐户,其中大小写确实很重要)。我认为该工具应该有一个忽略大小写的选项,适用于一组域名(或相反,只针对一组域名区分大小写)。因此,现在电子邮件地址JoE@caFÉ.fR已经被规范化为joe@xn--caf-dma.fr。

再次提出国际(也称非ASCII)电子邮件地址的问题。如果本地部分是非ASCII字符怎么办?例如像甲斐@黒川.日本这样的东西(免责声明:我不会说日语)。RFC 5322禁止这样做,但更近期的RFC支持这样做(请参见此维基百科文章)。很多语言没有大小写的概念。当它们有时,如果您想要改为小写形式,请确保使用适当的Unicode小写算法,这并不总是简单的。例如,在德语中,单词“Großes”的小写可能是“grosses”或“großes”(免责声明:我也不会说德语)。因此,此时电子邮件地址“Großes@caFÉ.Fr”应已归一化为“grosses@xn--caf-dma.fr”。
我没有详细阅读RFC 5322,但我认为电子邮件地址中也可能有注释,可以在本地部分的开头或结尾添加,例如(sir)john.lennon@beatles.com 或 john.lennon(ono)@beatles.com。这些注释应该被剥离(这将导致john.lennon@beatles.com)。剥离注释并不完全简单,因为我不知道该如何处理嵌套的注释,而且根据RFC(除非我弄错了),用双引号括起来的注释不应该被剥离。例如,以下电子邮件地址中的注释不应根据RFC被剥离:"john.(ono).lennon"@beatles.com。

一旦电子邮件被规范化,我会应用您建议的“特定于提供程序”的规则。例如,在GMail地址中去掉点并混合等效的域名(例如googlemail.com == gmail.com)。我认为我会将其与先前的规范化步骤保持真正分离。

请注意,Gmail还忽略加号(+)和之后的所有内容,例如s.m.i.t.h+hello_world@gmail.com等同于smith@gmail.com。

我不了解其他供应商的规则。问题是,这些规则可能随时发生变化,你需要跟踪所有这些规则。

我想这就是全部了。如果您有一些可用的代码,我会非常感兴趣看到它。

干杯!


1
谢谢您提供详细的答案!我确实编写了一个简单的清洁程序,并使用了上面提到的一些要点。在我的情况下,我将Gmail特定规则作为一个具体案例进行处理。关于注释的迷人之处,也会记在心里。 - StaxMan
很高兴为您服务。解析电子邮件地址确实不是一件容易的事情:维基百科关于电子邮件地址的页面详细地解释了这些内容。显然,Django的validate_email函数使用了一个正则表达式,从我所见,它并不完全符合RFC标准,例如它不允许john."ono".lennon@beatles.com,尽管它应该被允许。我刚刚注意到的另一个细节是:"postmaster"电子邮件地址是一个特殊情况,它始终不区分大小写。 - MiniQuark
1
我刚刚注意到域名中允许使用注释!不管怎样,我想知道有多少人实际上在他们的电子邮件地址中使用注释? - MiniQuark

5
我一直在使用Apache James Mime4J来解析电子邮件地址。
  1. 它可以正确处理(email address中的)括号注释,并将其从localPart和domainPart中移除。

  2. 它可以正确处理“带空格和引号”的以及+标记的localParts。

  3. 它有getLocalPart()和getDomainPart()方法。

  4. 然而,它不会对gmail的localParts进行规范化处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接