我们的网络应用程序具有一项功能,允许用户通过向特定电子邮件地址发送电子邮件来导入数据。当我们的应用程序收到电子邮件时,根据发件人的不同,会对其进行不同的处理。我们看到";发送者";字段,并将其与我们数据库中的用户相匹配。一旦确定了发送电子邮件的用户,我们将根据该用户的个人设置处理该电子邮件。
对于大多数用户来说,这通常运行良好。然而,某些用户抱怨他们的电子邮件没有得到处理。当我们查看它时,我们发现他们的电子邮件服务器正在向发件人的电子邮件地址添加信息,这导致电子邮件地址与数据库中用户表中的内容不匹配。例如,用户的电子邮件可能是数据库中的testuser@example.com
,但";发送者";我们收到的电子邮件中的字段将类似于btv1==502867923ab==testuser@example.com
。一些研究表明,这是由发件人的服务器使用的反弹地址标签验证(BATV)引起的。
我们需要能够从";发送者";提供给我们的字段,以便我们可以将其与用户表相匹配。这里的另一位开发人员编写了一个函数来实现这一点,并将其提交给我进行代码审查。这是他写的(C#):
private static string SanitizeEmailSender(string sender)
{
if (sender == null)
return null;
return System.Text.RegularExpressions.Regex.Replace(
sender,
@"^((btv1==.{11}==)|(prvs=.{9}=))",
"",
System.Text.RegularExpressions.RegexOptions.None);
}
这里的regex模式涵盖了我们在电子邮件日志中看到的特定情况。我担心正则表达式可能过于具体。btv1
和prvs
是这些标签中唯一使用的前缀吗?prvs=
后面总是正好有9个字符吗?除了BATV之外,我们还需要注意其他电子邮件发件人标记方案吗?我不想把这个修复程序投入生产,只是为了在下个月发现我们需要再次修复它,因为还有其他情况我们没有考虑。
我的直觉是只修改电子邮件地址,只包括最后一个=
之后的部分。然而,研究表明,=
是电子邮件地址中的一个有效字符,因此可能是用户规范电子邮件地址的一部分。我个人从未见过=
在某种标记或子寻址方案之外的电子邮件地址中使用,但你永远不会知道。墨菲定律表明,当我假设用户的电子邮件地址中永远不会有某个字符时,有这种地址的人会立即注册。
我的问题是:有没有一种行业公认的可靠方法来提取用户的规范电子邮件地址,给定一个更长的地址,其中可能包括BATV或其他标签如果做不到这一点,至少还有比目前更可靠的方法吗?或者我们所拥有的真的足够吗?
由于BATV添加的信息总是在BATV标记之前,并将信息分隔在两个==
字符串之间,因此我应该使用以下内容:
((btv1|prvs)==([^=]|=[^=])*==))
当然,=
符号被允许作为电子邮件地址中的有效字符,这是正确的,但这正是使用该序列(形成有效电子邮件地址)的原因。
如果您尝试进一步挖掘与电子邮件相关的RFC,您会发现MIME添加了一些结构,通过使用带引号的可打印功能,允许非ascii字符到电子邮件地址。需要阅读一些RFC来选择如何正确处理这些事情。
最后,为了回答您的问题,由于邮件服务器被授权修改/重写信封地址——这些是控制协议SMTP中用于邮件路由的地址——(sendmail甚至可以在邮件头字段中完成)您的问题的正确答案是没有可靠的方法(行业接受与否)来提取发件人的规范电子邮件地址。当邮件到达目标收件人时,地址会被重写,信息也会随之丢失。您无法恢复使用的原始地址。
最后,举例说明:
- Sender字段由最终SMTP收件人添加,以在电子邮件中包括信封发件人的地址(原始SMTP协议消息中用作
FROM: <sender@address.com>
的地址) - From字段由原始邮件客户端添加,用于标识消息的来源。此行为可以通过存在Resent from或Resent sender字段来修改,以防重新发送邮件。这些标识消息的重新发送
- 最后,发件人可以使用Reply-to标头来指示要发送到该地址的响应
要了解SMTP协议是如何工作的,请阅读密集的RFC-2821(SMTP协议)和RFC-2822(互联网邮件的格式)文档。
btv1和prvs是这些标签中唯一使用的前缀吗?
CCD_ 12是符合";元语法";在RFC中定义。btv1
是一个Barracuda设备Invalid Spoof Suppression重写,它不遵循BATV标准(因此使用双等号)。
一个只匹配所有BATV本地部分的正则表达式将是
[0-9A-Za-z-]+=[0-9A-Za-z-]+=.+@.+]
但这不会赶上梭鱼btv1
重写(和其他重写)
prvs=后面总是正好有9个字符吗?
不,规格上说有10个,但在野外最常见的是9个
除了BATV之外,我们还需要注意其他电子邮件发件人标记方案吗?
是,请参阅下文。
有没有一种行业公认的可靠方法来提取用户的规范电子邮件地址,给定一个更长的地址,其中可能包括BATV或其他标签?
无
通过查看各种代码库,看起来每个人都实现了自己的解决方案。一些复杂性来自于存在这一事实
- BATV重写
- BATV通过交换CCD_ 15和CCD_。下面是一个示例,显示了这些反向版本和一些代码,这些代码验证每个版本以查看它是否是prvs值,然后假设另一个是
loc-core
- 梭鱼非标准重写
- 其他非BATV重写,如
- SRS
- 谷歌转发
下面是一个单元测试,包含一个可能的发送方重写示例列表,下面是一些在野外发现的语法示例。
如果做不到这一点,至少还有比我们迄今为止更可靠的方法吗?或者我们所拥有的真的足够吗?
看起来最好的方法是像ezmlm-idx和rspamd那样处理每一种情况
您使用的正则表达式不包括
loc-core
和tag-val
逆转的prvs- 遵循规范的prv包含10个字符而不是9个字符
- SRS
- 谷歌转发