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

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

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

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


当前回答

我用这个;

^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$

其他回答

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

/^("(?:[!#-\[\]-\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为域名定义了一个允许的语法,允许当前已知的名称无效。这也允许域名将来成为合法的。这不应该是一个问题,因为这应该以与不存在的域名相同的方式处理。

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

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

这是电子邮件的正则表达式之一:

^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$

这一切都取决于你想要的准确度。出于我的目的,我只是想避开bob@aol.com(电子邮件中的空格)或steve(完全没有域名)或mary@aolcom(在.com之前没有句点),我使用

/^\S+@\S+\.\S+$/

当然,它会匹配不是有效电子邮件地址的内容,但这是一个常见的简单错误问题。

可以对该正则表达式进行任意数量的更改(其中一些在这个答案的注释中),但它很简单,易于理解,是一个很好的第一次尝试。

在Perl 5.10或更高版本中很容易:

/(?(DEFINE)
   (?<address>         (?&mailbox) | (?&group))
   (?<mailbox>         (?&name_addr) | (?&addr_spec))
   (?<name_addr>       (?&display_name)? (?&angle_addr))
   (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
   (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
                                          (?&CFWS)?)
   (?<display_name>    (?&phrase))
   (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

   (?<addr_spec>       (?&local_part) \@ (?&domain))
   (?<local_part>      (?&dot_atom) | (?&quoted_string))
   (?<domain>          (?&dot_atom) | (?&domain_literal))
   (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                 \] (?&CFWS)?)
   (?<dcontent>        (?&dtext) | (?&quoted_pair))
   (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

   (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
   (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
   (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
   (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

   (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
   (?<quoted_pair>     \\ (?&text))

   (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
   (?<qcontent>        (?&qtext) | (?&quoted_pair))
   (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                        (?&FWS)? (?&DQUOTE) (?&CFWS)?)

   (?<word>            (?&atom) | (?&quoted_string))
   (?<phrase>          (?&word)+)

   # Folding white space
   (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
   (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
   (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
   (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
   (?<CFWS>            (?: (?&FWS)? (?&comment))*
                       (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

   # No whitespace control
   (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

   (?<ALPHA>           [A-Za-z])
   (?<DIGIT>           [0-9])
   (?<CRLF>            \x0d \x0a)
   (?<DQUOTE>          ")
   (?<WSP>             [\x20\x09])
 )

 (?&address)/x

您可以使用jQuery Validation插件使用的方法:

/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i