System.Net.MailMessage可以允许一些无效的电子邮件地址格式。

5
许多人可能已经知道,正确验证电子邮件地址可能会是一场噩梦。你可以整天搜索符合当前RFC标准的C#正则表达式,但你会发现不同的正则表达式会给出不同的结果。
如果你查看http://en.wikipedia.org/wiki/Email_address#Local_part,你会发现在本地部分开头或结尾的句点是不允许的。两个连续的句点也是不允许的。然而,以下NUnit测试证明了System.Net.MailMessage允许你为一些无效的电子邮件地址格式实例化一个MailMessage对象。
[Test]
[TestCase(@"foobar@exampleserver")] //technically valid from the wiki article
[TestCase(@"jsmith@[192.168.2.1]")] //technically valid from the wiki article
[TestCase(@"niceandsimple@example.com")] //vanilla email address
[TestCase(@"very.common@example.com")] //also standard
[TestCase(@"a.little.lengthy.but.fine@dept.example.com")] //long with lots of periods
[TestCase(@"disposable.style.email.with+symbol@example.com")] //disposable with the + symbol
[TestCase(@"other.email-with-dash@example.com")] //period and dash in local part
[TestCase(@"user-test-hyphens@example-domain.com")] //lots of hyphens
[TestCase(@"!#$%&'*+-/=?^_`{|}~@example-domain.com")] //all these symbols are allowed in local part
[TestCase(@"ër_%لdev@gكňil.com")] //characters outside the ascii range are permitted
[TestCase(@"""abcdefghixyz""@example.com")] //technically valid
//[TestCase(@"abc.""defghi"".xyz@example.com")] //technically valid, but .NET throws exception
public void CanCreateMailMessageObjectTest(string emailAddress)
{
     var mailMessage = new System.Net.Mail.MailMessage("noreply@example.com", emailAddress);  
}

除了最后一个测试用例外,以上所有测试用例都通过了。
[Test]
[TestCase(@".test@example.com")] //leading period
[TestCase(@"test.@example.com")] //period at end of local part <---FAIL
[TestCase(@"test..example@example.com")] //double period in local part <---FAIL
[TestCase(@"foobar@example!#$%^&*()=server.com")] //special characters in domain part
[TestCase(@"Abc.example.com")] //No @ separating local and domain part
[TestCase(@"A@b@c@example.com")] //more than one @ symbol
[TestCase(@"just""not""right@example.com")] //quoted strings must be dot separated
[TestCase(@"a""b(c)d,e:f;g<h>i[j\k]l@example.com")] //special symbols "(),:;<>@[\] not inside quotes
[TestCase(@"[test@example.com")] //leading special symbol in local part
[TestCase(@"this is""not\allowed@example.com")] //spaces not in quotes
[TestCase(@"this\ still\""not\\allowed@example.com")] //backslashes not in quotes
[ExpectedException(typeof (System.FormatException))]
public void CannotCreateMailMessageObjectTest(string emailAddress)
{
    var mailMessage = new System.Net.Mail.MailMessage("noreply@example.com", emailAddress);
}

为什么 test.@example.comtest..example@example.com 没有抛出 System.FormatException 异常?是 Microsoft 还是 Wikipedia 错了?是否有任何电子邮件地址被允许使用尾随句号或双句号?我应该允许它们通过验证吗?我已经设置了适当的异常处理,以便我的电子邮件投递服务在发生异常时继续运行,但我想排除无效或保证会引发异常的电子邮件地址。
2个回答

3
没有解释为什么,但是System.Net.Mail.MailAddress的MSDN文档指出支持以下邮件地址格式:
MailAddress类支持以下邮件地址格式: ... 用户名称中的连续和尾随点。例如,user...name..@host。
所以这不是MailAddress类中的错误 - 明确支持该表单。但我不知道支持它们的原因。我认为可能有些系统实际上接受它们,而微软觉得需要支持这种情况。
另一方面,虽然我可以理解提供一些电子邮件地址验证的必要性,但我个人认为在验证中没有必要过于严格。系统需要处理坏的但语法正确的地址。另一方面,似乎在本地部分的重复周期或周期末可能是常见的打字错误,所以我可以理解为什么您可能希望它们无法通过验证。

可能是常见的打字错误。没错,我因为这个原因会让它们失败。我主要只想让那些明显无效或者我知道不会被投递的地址失败,因为MailAddress/MailMessage会抛出异常(虽然我处理了,但还是...)。 - jreancsu

0

既然RFC定义了标准,那么微软的实现就是不正确的。

如果您想进行更好的验证,请尝试我在此答案中发布的验证器,以回答C#电子邮件地址验证的问题。

它应该可以正确(严格)地验证您可能遇到的任何“正常”格式的电子邮件地址,格式为local-part@domain,但它不支持新的允许的非ASCII样式。我不能保证自从我写它以来,一点腐烂没有发生,因为它已经有几年了,而且电子邮件RFC已经更新。

local-part必须未引用:它不支持引用的本地部分或引用的标签。

至于域部分,我的验证器不支持IPv4或IPv6文字(虽然添加这些内容并不难)。

如果您想允许任何/所有符合RFC的地址,则会变得更加困难。


感谢您发布了三年半前的解决方案,但那并不是我正在寻找的。我可以从FluentValidation和Microsoft获取正则表达式,或者编写自己的正则表达式,但问题在于它们都不同。这篇文章并没有要求正则表达式,而是询问为什么MailMessage没有引发FormatException。 - jreancsu

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