多年来,我慢慢地开发了一个正则表达式,它可以正确验证大多数电子邮件地址,假设它们不使用IP地址作为服务器部分。

我在几个PHP程序中使用它,而且大多数时候都可以使用。然而,不时有人与我联系,他们对使用它的网站有问题,我最终不得不做出一些调整(最近我意识到我不允许四个字符的TLD)。

你有或见过验证电子邮件的最佳正则表达式是什么?

我见过几种使用函数的解决方案,这些函数使用了几个较短的表达式,但我宁愿在简单函数中使用一个长的复杂表达式,而不是在更复杂的函数中使用几个短表达式。


当前回答

public bool ValidateEmail(string sEmail)
{
    if (sEmail == null)
    {
        return false;
    }

    int nFirstAT = sEmail.IndexOf('@');
    int nLastAT = sEmail.LastIndexOf('@');

    if ((nFirstAT > 0) && (nLastAT == nFirstAT) && (nFirstAT < (sEmail.Length - 1)))
    {
        return (Regex.IsMatch(sEmail, @"^[a-z|0-9|A-Z]*([_][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*(([_][a-z|0-9|A-Z]+)*)?@[a-z][a-z|0-9|A-Z]*\.([a-z][a-z|0-9|A-Z]*(\.[a-z][a-z|0-9|A-Z]*)?)$"));
    }
    else
    {
        return false;
    }
}

其他回答

我使用

^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

这是RegularExpressionValidator在ASP.NET中使用的值。

电子邮件地址的正则表达式为:

/^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u

此正则表达式与RFC 5321、RFC 5322和RFC 6532中指定的非过时电子邮件地址的地址规范ABNF 100%相同。

此外,您必须验证:

电子邮件地址格式为UTF-8(或ASCII,如果无法发送到国际化电子邮件地址)地址不超过320个UTF-8字节用户部分(第一个匹配组)不超过64个UTF-8字节域部分(第二个匹配组)不超过255个UTF-8字节

完成所有这些的最简单方法是使用现有函数。在PHP中,请使用filter_VALIDATE_EMAIL和filter_FLAG_EMAIL_UNICODE(如果可以发送到国际化电子邮件地址)查看filter_var函数:

$email_valid = filter_var($email_input, FILTER_VALIDATE_EMAIL, FILTER_FLAG_EMAIL_UNICODE);

然而,也许您正在构建这样一个函数,实际上实现这一点的最简单方法是使用正则表达式。

记住,这只验证电子邮件地址不会导致语法错误。验证地址是否可以接收电子邮件的唯一方法是实际发送电子邮件。

接下来,我将讨论如何生成此正则表达式。


我写了一个新的答案,因为这里的大多数答案都犯了这样一个错误:要么指定了一个限制性太强的模式(因此没有很好地老化);或者它们呈现一个正则表达式,该表达式实际上与MIME消息的标头匹配,而不是电子邮件地址本身。

只要没有递归部分,从ABNF生成正则表达式是完全可能的。

RFC 5322规定了在MIME消息中发送什么是合法的;将此视为合法电子邮件地址的上限。

然而,完全遵循ABNF将是一个错误:这种模式在技术上表示了如何在MIME消息中编码电子邮件地址,并允许字符串不属于电子邮件地址,如折叠空格和注释;它还支持不合法生成的过时表单(但服务器出于历史原因读取)。电子邮件地址不包括这些。

RFC 5322解释了:

原子和点原子都被解释为单个单元,包括组成它的字符串。语义上,可选其余角色周围的评论和FWS不属于原子;原子只是一个原子中的一行文本字符,或点原子中的atext和“.”字符。

在某些定义中,将有非终端的名称以“obs-”开头。这些“obs-”元素是指在第4节中过时的语法。在所有情况下,这些产品为了生成合法的互联网信息,不得用作此类信息的一部分。

如果您从RFC 5322中的addr规范中删除CFWS、BWS和obs-*规则,并对结果执行一些优化(我使用了“green”),则可以生成此正则表达式,用斜线引用并锚定(适用于ECMAScript和兼容方言,为清晰起见,添加了换行符):

/^("(?:[!#-\[\]-~]|\\[\t -~])*"|[!#-'*+\-/-9=?A-Z\^-~](?:\.?[!#-'*+\-/-9=?A-Z\^-~])*)
@([!#-'*+\-/-9=?A-Z\^-~](?:\.?[!#-'*+\-/-9=?A-Z\^-~])*|\[[!-Z\^-~]*\])$/

这只支持ASCII电子邮件地址。要支持RFC 6532国际化电子邮件地址,请将~字符替换为\u{10FFFF}(PHP,带u标志的ECMAScript)或\uFFFF(用于UTF-16实现,如.NET和旧版ECMAScript/JavaScript):

/^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u

这是有效的,因为我们使用的ABNF不是递归的,因此形成了可以转换为正则表达式的非递归正则语法。

它是这样分解的:

用户部分(@之前)可以是点原子或带引号的字符串“([!#-\[\]-~]|\\[\t-~])*”指定用户的引号字符串形式,例如root@home“@example.com。它允许双引号内的任何非控制字符;但空格、制表符、双引号和反斜杠必须用反斜杠转义。[!#-'*+\-/-9=?A-Z\^-~]是用户点原子的第一个字符。(\.?[!#-'*+\-/-9=?A-Z\^-~])*与点原子的其余部分匹配,允许点(除了在另一个点之后或作为最终字符)。@表示域。域部分可以是点原子或域文字。[!#-'*+\-/-9=?A-Z\^-~](\.?[!#-'*+\-/-9=?A-Z \^-~])*与上面的点原子形式相同,但这里它表示域名和IPv4地址。\[[!-Z\^-~]*\]将匹配IPv6地址和主机名的未来定义。

此正则表达式允许所有符合规范的电子邮件地址,并且可以在MIME消息中逐字使用(除了行长度限制,在这种情况下必须添加折叠空格)。

这还设置了非捕获组,使得match[1]将是用户,match[2]将是主机。(但是,如果匹配项[1]以双引号开头,则过滤掉反斜杠转义符以及开头和结尾双引号:“root”@example.com和root@example.com识别同一收件箱。)

最后,请注意,RFC 5321对电子邮件地址的长度设置了限制。用户部分最多可为64字节,域部分最多为255字节。包括@字符在内,整个地址的限制为320字节。地址是UTF-8编码后的字节数;而不是字符。

注意,RFC 5322 ABNF为域名定义了一个允许的语法,允许当前已知的名称无效。这也允许域名将来成为合法的。这不应该是一个问题,因为这应该以与不存在的域名相同的方式处理。

始终考虑用户键入的电子邮件地址有效,但他们无法访问的可能性。验证电子邮件地址的唯一简单方法是发送电子邮件。

这是改编自我的文章电子邮件地址和语法。

我们使用了http://www.aspnetmx.com/几年来取得了一定的成功。您可以选择要验证的级别(例如语法检查、域检查、MX记录或实际电子邮件)。

对于前端表单,我们通常会验证域是否存在以及语法是否正确,然后在进行批量邮件发送之前,我们会进行更严格的验证以清理数据库。

^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$

这与99.99%的电子邮件地址相匹配,包括一些较新的顶级域名扩展,如信息、博物馆、名称等。它还允许将电子邮件直接绑定到IP地址。

根据我的理解,它很可能会被。。。

/^([a-z0-9_-]+)(@[a-z0-9-]+)(\.[a-z]+|\.[a-z]+\.[a-z]+)?$/is