如何使用正则表达式验证电子邮件地址?


3309

多年来,我逐渐发展了 正则表达式,可以假定MOST电子邮件地址未将IP地址用作服务器部分,因此可以正确地验证这些电子邮件地址。

我在几个PHP程序中使用了它,并且大多数时候都可以使用。但是,有时会遇到某个使用它的网站出现问题的人与我联系,最终我不得不进行一些调整(最近我意识到我不允许使用4个字符的TLD)。

您已经或看到的用于验证电子邮件的最佳正则表达式是什么?

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



5
可以验证IDNA格式正确的正则表达式不适用于stackexchange。(规范化规则确实是曲折的,尤其不适用于正则表达式处理)
Jasen


正则表达式可能是可变的,因为在某些情况下,电子邮件骗局可以包含一个空格,而在其他情况下,它不能包含任何空格。
Ṃųỻịgǻňạcểơửṩ

Answers:


2438

由于其长度,完全符合RFC 822的正则表达式效率低下且晦涩难懂。幸运的是,RFC 822被取代了两次,当前电子邮件地址规范为RFC 5322。RFC 5322导致了一个正则表达式,如果研究几分钟,它可以被理解并且对于实际使用足够有效。

可以在页面顶部的http://emailregex.com/上找到一个符合RFC 5322的正则表达式,但是它使用的IP地址模式在Internet上浮动并且存在一个错误,该错误允许00在地址栏中输入任何未签名的字节十进制值以点分隔的地址,这是非法的。它的其余部分似乎与RFC 5322语法一致,并通过了使用grep -Po,包括案例,域名,IP地址,错误的域名以及带引号和不带引号的帐户名。

纠正00IP模式中的错误后,我们获得了一个有效且相当快速的正则表达式。(对于实际代码,请删除渲染的版本,而不是降价版本。)

(?:[a-z0-9!#$%&'* + / =?^ _`{|}〜-] +(?:\。[a-z0-9!#$%&'* + / =?^ _`{|}〜-] +)* |“(?:[\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21 \ x23- \ x5b \ x5d- \ x7f] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7f])*))@(?:(?:[a-z0-9](?:[a-z0-9-] * [a-z0 -9])?\。)+ [a-z0-9](?:[a-z0-9-] * [a-z0-9])?| \((?:(?:( 2(5 [0-5] | [0-4] [0-9])| 1 [0-9] [0-9] | [1-9]?[0-9]))\。){3}( ?:( 2(5 [0-5] | [0-4] [0-9])| 1 [0-9] [0-9] | [1-9]?[0-9])| [ a-z0-9-] * [a-z0-9]:(?:[\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21- \ x5a \ x53- \ x7f] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7f])+)\])

要么:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

这是上述regexp 的有限状态机,比regexp本身更清晰 enter image description here

Perl和PCRE(例如在PHP中使用的正则表达式库)中更复杂的模式可以正确解析RFC 5322。Python和C#也可以做到这一点,但是它们使用的语法与前两个语法不同。但是,如果您被迫使用功能较弱的模式匹配语言之一,那么最好使用真正的解析器。

同样重要的是要理解,根据RFC对其进行验证绝对不会告诉您该地址是否确实存在于提供的域中,或者输入地址的人是否是其真实所有者。人们一直以这种方式签署邮件列表。需要进行更高级验证的修补程序,包括向该地址发送一条消息,其中包含要与该地址输入同一网页的确认令牌。

确认令牌是知道您获得输入者地址的唯一方法。这就是为什么大多数邮件列表现在都使用该机制来确认注册的原因。毕竟,任何人都可以放下president@whitehouse.gov,甚至可以将其解析为合法的,但不可能是另一端的人。

对于PHP,你应该使用给定的模式验证与PHP的电子邮件地址,正道从我引述如下:

存在某种危险,即通常的用法和广泛的草率编码将为电子邮件地址建立事实上的标准,该标准比记录的正式标准更具限制性。

这并不比所有其他非RFC模式都好。它甚至不是足够聪明,可以处理RFC 822,更不用说RFC 5322 这一个,但是,是。

如果您想花哨和学究,请实施一个完整的状态引擎。正则表达式只能充当基本过滤器。正则表达式的问题在于,告诉某人其完全有效的电子邮件地址是无效的(误报),因为从用户的角度来看,您的正则表达式无法处理它只是不礼貌和不礼貌。用于此目的的状态引擎既可以验证甚至更正电子邮件地址,否则该地址将被视为无效,因为它会根据每个RFC分解电子邮件地址。这样可以带来更愉悦的体验,例如

指定的电子邮件地址“ myemail @ address,com”无效。您是说“ myemail@address.com”吗?

另请参阅验证电子邮件地址,包括评论。或比较验证正则表达式的电子邮件地址

Regular expression visualization

Debuggex演示


179
您说:“没有好的正则表达式。” 这是通用还是特定于电子邮件地址验证?
Tomalak

37
@Tomalak:仅用于电子邮件地址。作为Bortzmeyer做了大量表示,RFC非常复杂
六合

37
您提到的Linux期刊文章在几个方面实际上是错误的。特别是Lovell显然没有阅读RFC3696的勘误表,并在RFC的已发布版本中重复了一些错误。更多信息,请访问:dominicsayers.com/isemail
Dominic Sayers 2009年

9
杰夫·阿特伍德(Jeff Atwood)在此博文中使用了一个可爱的正则表达式来验证所有有效的电子邮件地址:codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea 2010年

5
请注意,当前的HTML5规范包括用于电子邮件类型输入验证的正则表达式和ABNF,故意比原始RFC更具限制性。
同步2014年

745

您不应使用正则表达式来验证电子邮件地址。

而是使用MailAddress类,如下所示:

try {
    address = new MailAddress(address).Address;
} catch(FormatException) {
    // address is invalid
}

MailAddress班采用了BNF解析器完全按照RFC822验证地址。

如果您打算使用MailAddress验证电子邮件地址,请注意,这种方法也接受电子邮件地址的显示名称部分,而这可能并不是您想要的。例如,它接受以下字符串作为有效的电子邮件地址:

  • “ user1@hotmail.com; user2@gmail.com”
  • “ user1@hotmail.com; user2@gmail.com; user3@company.com”
  • “用户显示名称user3@company.com”
  • “ user4 @ company.com”

在某些情况下,仅将字符串的最后一部分解析为地址。其余的就是显示名称。要获得不带任何显示名称的纯电子邮件地址,您可以对照原始字符串检查规范化地址。

bool isValid = false;

try
{
    MailAddress address = new MailAddress(emailAddress);
    isValid = (address.Address == emailAddress);
    // or
    // isValid = string.IsNullOrEmpty(address.DisplayName);
}
catch (FormatException)
{
    // address is invalid
}

此外,末尾带有点的地址,例如 user@company. MailAddress一样接受。

如果您真的想使用正则表达式,则在这里

(?:(?:\ r \ n)?[\ t])*(?:(?:(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031 ] +(?:(?:(?:\ r \ n)?[\ t]
)+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]])))|“((?:[^ \” \ r \\] | \\。 |(?:(?:\ r \ n)?[\ t]))*“((?:( ?:
\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\ \“。\ [\] \ 000- \ 031] +(?:(?:(
?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]]))|“(? ^ \“ \ r \\] | \\。|(??((?:\ r \ n)?[ 
\ t]))*“(?:(?:\ r \ n)?[\ t])*))* @(?:(?:\ r \ n)?[\ t])*(?: [^()<> @,;:\\“。\ [\] \ 000- \ 0
31] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\ ]]))| \ [([[^ \ [\] \ r \\] | \\。)* \
](?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^() <> @,; :: \\“。\ [\] \ 000- \ 031] +
(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]]) )| \ [([[^ \ [\] \ r \\] | \\。)* \](?:
(?:\ r \ n)?[\ t])*)))* |(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?: (?:(?:\ r \ n)?[\ t])+ | \ Z
|(?= [\ [“()<> @,;:\\”。\ [\]])))|“(?:[^ \” \ r \\] | \\。|(?:( ?:\ r \ n)?[\ t]))*“(?:(?:\ r \ n)
?[\ t])*)* \ <(?:(?:\ r \ n)?[\ t])*(?:@(?:[^()<> @,;:\\“。 \ [\] \ 000- \ 031] +(?:(?:(?:\
r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]]))| \ [([^ \ [\ ] \ r \\] | \\。)* \](?:(?:\ r \ n)?[
 \ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)
?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]]))| \ [([^ \ [\] \ r \ \] | \\。)* \](?:(?:\ r \ n)?[\ t]
)*))*(?:,@(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[
 \ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]])))\\ [([^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*
)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031 ] +(?:(?:(?:\ r \ n)?[\ t]
)+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]])))| \ [([^ \ [\] \ r \\] | \\ 。)* \](?:(?:\ r \ n)?[\ t])*))*)
*:(?:(?:\ r \ n)?[\ t])*)?(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] + (?:(?:(?:\ r \ n)?[\ t])+
| \ Z |(?= [\ [“()<> @,; :: \\”。\ [\]])))|“(?:[^ \” \ r \\] | \\。|( ?:(?:\ r \ n)?[\ t]))*“(?:(?:\ r
\ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“ 。\ [\] \ 000- \ 031] +(?:(?:( ?:
\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,; :: \\”。\ [\]]))|“(?:[^ \ “ \ r \\] | \\。|(?:(?:\ r \ n)?[\ t
]))*“(?:(?:\ r \ n)?[\ t])*))* @(?:(?:\ r \ n)?[\ t])*(?:[^ ()<> @,;:\\“。\ [\] \ 000- \ 031
] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\] ]))| \ [([[^ \ [\] \ r \\] | \\。)* \](
?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?
:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]])))|| \ [([^ \ [\] \ r \\] | \\。)* \](?:(?
:\ r \ n)?[\ t])*))* \>(?:(?:\ r \ n)?[\ t])*)|(?:[^()<> @ ,; :\\“。\ [\] \ 000- \ 031] +(?:(?
:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]]))|“(? :[^ \“ \ r \\] | \\。|(??((?:\ r \ n)?
[\ t]))*“(?:(?:\ r \ n)?[\ t])*)*:(?:(?:\ r \ n)?[\ t])*(? (?:(?:[^()<> @,;:\\“。\ [\] 
\ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\” 。\ [\]]))|“((?:[^ \” \ r \\] |
\\。|(?:(?:\ r \ n)?[\ t]))*“(?:(?:\ r \ n)?[\ t])*)(?:\。(? :(?:\ r \ n)?[\ t])*(?:[^()<>

@,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [ “()<> @,; :: \\”。\ [\]]))|“
(?:[^ \“ \ r \\] | \\。|((?:(?:\ r \ n)?[\ t]))*”(?:(?:\ r \ n)?[ \ t])*))* @(?:(?:\ r \ n)?[\ t]
)*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t]) + | \ Z |(?= [\ [“()<> @,;:\\
“。\ [\]]))| \ [([^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])* )(?:\。(?:(?:\ r \ n)?[\ t])*(?
:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [
\]])))\\ [([[^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*))* | (?:[^()<> @,;:\\“。\ [\] \ 000-
\ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [ \]]))||((?:[^ \“ \ r \\] | \\。|(
?:(?:\ r \ n)?[\ t]))*“(?:(?:\ r \ n)?[\ t])*)* \ <(?:(?:\ r \ n)?[\ t])*(?:@(?:[^()<> @,;;
:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [”() <> @,; :: \\“。\ [\]]))| \ [([
^ \ [\\\ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“
。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @, ;:\\“。\ [\]]))| \ [([^ \ [\
] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)))*(?:,@(?:(?:\ r \ n )?[\ t])*(?:[^()<> @,;:\\“。\
[\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;: \\“。\ [[\]]))| \ [([^ \ [\] \
r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] 
\ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\” 。\ [\]]))| \ [([^ \ [\] \ r \\]
| \\。)* \](?:(?:\ r \ n)?[\ t])*))*)*:(?:(?:\ r \ n)?[\ t])* )?(?:[^()<> @,;:\\“。\ [\] \ 0
00- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。 \ [\]]))|“(?:[^ \” \ r \\] | \\
。|(?:(?:\ r \ n)?[\ t]))*“((?:(?:\ r \ n)?[\ t])*)(?:\。(?:( ?:\ r \ n)?[\ t])*(?:[^()<> @,
;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [”( )<> @,; :: \\“。\ [\]])))”((?
:[^ \“ \ r \\] | \\。|(??((?:\ r \ n)?[\ t]))*”(??((?:\ r \ n)?[\ t ])*))* @(?:(?:\ r \ n)?[\ t])*
(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。
\ [\]]))| \ [([[^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)( ?:\。(?:(?:\ r \ n)?[\ t])*(?:[
^()<> @,; :: \\“。\ [\] \ 000- \ 031] +(?:(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |( ?= [\ [“()<> @,;:\\”。\ [\]
]))| \ [([[^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*))* \>( ?:(?:\ r \ n)?[\ t])*)(?:,\ s *(
?:(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t]) + | \ Z |(?= [\ [“()<> @,;:\\
“。\ [\]]))|”(?:[^ \“ \ r \\] | \\。|(?:(?:\ r \ n)?[\ t]))*”(? :(?:\ r \ n)?[\ t])*)(?:\。(?:(
?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(? :\ r \ n)?[\ t])+ | \ Z |(?= [
\ [“()<> @,;:\\”。\ [\]]))|“(?:[^ \” \ r \\] | \\。|(?:(?:\ r \ n)?[\ t]))*“(?:(?:\ r \ n)?[\ t
])*))* @(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t
])+ | \ Z |(?= [\ [“()<> @,;:\\”。\ [\]])))| \ [([^ \ [\] \ r \\] | \\ \。)* \](?:(?:\ r \ n)?[\ t])*)(?
:\。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +( ?:(?:(?:\ r \ n)?[\ t])+ |
\ Z |(?= [\ [“()<> @,; :: \\”。\ [\]])))| \ [([^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*))* |(?
[^()<> @,; :: \\“。\ [\] \ 000- \ 031] +(?:(?:(?:(?:\ r \ n)?[\ t])+ | \ Z | (?= [\ [“()<> @,;:\\”。\ [\
]]))|“(?:[^ \” \ r \\] | \\。|(?:(?:\ r \ n)?[\ t]))*“(?:(?:\ r \ n)?[\ t])*)* \ <(?:(?:\ r \ n)
?[\ t])*(?:@(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“
()<> @,; :: \\“。\ [\]]))| \ [([[^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)
?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)? [\ t])+ | \ Z |(?= [\ [“()<>

@,; :: \\“。\ [\]]))| \ [([[^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)? [\ t])*))*(?:,@(?:(?:\ r \ n)?[
 \ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,
;:\\“。\ [\]]))| \ [([^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])*)(?:\。(?:(?:\ r \ n)?[\ t]
)*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t]) + | \ Z |(?= [\ [“()<> @,;:\\
“。\ [\]]))| \ [([^ \ [\] \ r \\] | \\。)* \](?:(?:\ r \ n)?[\ t])* ))*)*:(?:(?:\ r \ n)?[\ t])*)?
(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [“()<> @,;:\\”。
\ [\]]))|“(?:[^ \” \ r \\] | \\。|(?:(?:\ r \ n)?[\ t]))*“(?:( ?:\ r \ n)?[\ t])*)(?:\。(?:( ?:
\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])+ | \ Z |(?= [\ [
“()<> @,; :: \\”。\ [\]]))|“(?:[?\ [\ r \\] | \\。|(?:(?:\ r \ n) ?[\ t]))*“(?:(?:\ r \ n)?[\ t])
*))* @(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?:(?:(?:\ r \ n)?[\ t])
+ | \ Z |(?= [\ [“()<> @,; :: \\”。\ [\]])))| \ [([^ \ [\] \ r \\] | \\。 )* \](?:(?:\ r \ n)?[\ t])*)(?:\
。(?:(?:\ r \ n)?[\ t])*(?:[^()<> @,;:\\“。\ [\] \ 000- \ 031] +(?: (?:(?:\ r \ n)?[\ t])+ | \ Z
|(?= [\ [“()<> @,;:\\”。\ [\]])))| \ [([^ \ [\] \ r \\] | \\。)* \] (?:(?:\ r \ n)?[\ t])*))* \>(?:(
?:\ r \ n)?[\ t])*))*)?; \ s *)

26
您会发现,.NET 4.0中的MailAddress类比以前的版本在验证电子邮件地址方面要好得多。我对此做了一些重大改进。
Jeff Tucker,2009年

7
我认为...对于更简单的ID来说不起作用。a @ b无法验证。ar@b.com仅匹配到ar @ b为止,.com不匹配。但是,类似“我是我” @ [10.10.10.10]的确可以工作!:)
Raze

5
请注意,这些符合RFC的正则表达式验证器将通过许多您可能不希望接受的电子邮件地址,例如“ a <body / onload = alert(' lol.com? ' +document.cookies)@aa> “,这是perl的Email :: Valid(使用大量正则表达式)中的有效电子邮件地址,并且可以用于XSS rt.cpan.org/Public/Bug/Display.html?id=75650
马修·洛克

9
@MatthewLock:这并不比差fake@not-a-real-domain.name。您不得依赖电子邮件验证来阻止XSS。
SLaks 2012年

10
@MatthewLock:否。您需要转义 SQL查询(或者更好的是使用参数)。消毒不是适当的防御措施。
SLaks

535

这个问题被问了很多,但是我认为您应该退后一步,问自己为什么要在语法上验证电子邮件地址?真正的好处是什么?

  • 它不会捕获常见的错字。
  • 它不会阻止人们输入无效或伪造的电子邮件地址,或输入其他人的地址。

如果要验证电子邮件的正确性,则别无选择,只能发送确认电子邮件并让用户回复。在许多情况下,出于安全原因或出于道德原因,无论如何您都必须发送确认邮件(因此,您不能例如违反某人的意愿而签署某项服务)。


91
可能值得检查一下他们是否在客户端验证中向字段中输入了something @ something只是为了捕捉简单的错误-但总的来说您是对的。
马丁·贝克特

8
马丁,我给您+1,后来才读到foobar @ dk是有效的电子邮件。看起来不是很好,但是如果您想同时符合RFC并使用常识,则应检测到此类情况,并要求用户确认正确。
philfreo

105
@olavk:如果有人输入错字(例如me@hotmail),显然他们不会收到您的确认电子邮件,那么他们在哪里?他们不在您的网站上了,他们想知道为什么他们无法注册。其实不,他们不是-他们已经完全忘记了你。但是,如果您可以在正则表达式仍在您身边时对其进行基本的完整性检查,那么他们可以立即捕获到该错误,并且您的用户很满意。
尼克

5
@JacquesB:你说得很对。仅仅因为它通过了RFC,并不意味着它确实是该用户的地址。否则,所有这些president@whitehouse.gov地址都表示一个非常忙的总司令。:)
tchrist

39
它不必是黑色或白色。如果电子邮件看起来不正确,请告知用户。如果用户仍然想继续,请让他。不要强迫用户遵守您的正则表达式,而应使用正则表达式作为工具来帮助用户知道可能有错误。
ninjaneer 2014年

354

这完全取决于您想要的精度。就我的目的而言,我只是想避免出现诸如bob @ aol.com(电子邮件中的空格)或steve(完全没有域)或mary@aolcom(.com之前没有句号)之类的东西,我使用

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

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

可以对该正则表达式进行多种更改(某些答案在此答案的注释中),但是它很简单,易于理解,是一个很好的初次尝试。


6
它与foobar @ dk(这是一个有效且有效的电子邮件地址)不匹配(尽管可能大多数邮件服务器不会接受它或将添加something.com。)
bortzmeyer

3
是的,它会的。我建议您自己尝试。$ perl -le'print q{foo@bar.co.uk} =〜/^\S+@\S+\.\S+$/?q {Y}:q {N}'
Andy Lester,2009年

7
@Richard: .包含在中\S
David Thornley,2009年

43
JJJ:是的,它会匹配很多废话。它也将匹配&$ *#$(@ $ 0(%))$#。)&*)(* $。对我来说,我更喜欢捕捉像奇怪的手指错别字,而mary@aolcom不是我完全是垃圾。 YMMV。–
Andy Lester

5
只是为了控制@迹象:/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
克里斯·

338

这取决于您的最佳含义:如果您要谈论捕获每个有效的电子邮件地址,请使用以下命令:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
.\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html)如果您正在寻找更简单的方法,但可以捕获大多数有效的电子邮件地址,请尝试以下方法:

"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

编辑:从链接:

此正则表达式将仅验证删除了任何注释并用空格替换的地址(由模块完成)。


10
它不匹配所有地址,必须先转换一些地址。在链接中:“此正则表达式将仅验证删除了任何注释并替换为空白的地址(此操作由模块完成)。”
Chas。Owens

47
您能给我一个email address错误地通过第二个例子但被较长的正则表达式捕获的例子吗?
Lazer 2010年

4
尽管我曾经很喜欢它,但这是RFC 822验证程序,而不是RFC 5322验证程序。
tchrist

24
@Lazer in..valid @ example.com是一个简单的示例。您不允许在本地部分中使用两个连续的不带引号的点。
兰达·施瓦兹

5
@Mikhail perl,但您实际上不应使用它。
好人2013年

287

[更新]我已经在这里整理了有关电子邮件地址验证的所有信息:http : //isemail.info,它现在不仅可以验证电子邮件地址,还可以诊断电子邮件地址问题。我同意这里的许多评论,即验证仅是答案的一部分。请参阅http://isemail.info/about上的文章。

据我所知,is_email()仍然是唯一可以明确告诉您给定字符串是否为有效电子邮件地址的验证器。我已经在http://isemail.info/上载了新版本。

我整理了Cal Henderson,Dave Child,Phil Haack,Doug Lovell,RFC5322和RFC 3696的测试用例。总共有275个测试地址。我对所有可以找到的免费验证程序进行了所有这些测试。

随着人们增强其验证器,我将尝试使此页面保持最新。感谢Cal,Michael,Dave,Paul和Phil在汇编这些测试和对我自己的验证程序的建设性批评方面所提供的帮助和合作。

人们应该特别注意针对RFC 3696勘误表。实际上,其中三个规范示例是无效地址。地址的最大长度为254或256个字符,而不是 320。


这个验证器似乎也是正确的。[...时间流逝...]嗯,看起来它只是RFC 5322,而不是3693或勘误表。
tchrist

1
非常好。在这里,我们不仅获得了一篇不错的文章,还获得了一个验证测试人员以及一个可供下载的库。好答案!
bgmCoder

您的验证程序不支持punycode(RFC 3492)。name@öäü.at可以是有效地址。(其翻译为name@xn--4ca9at.at)
约瑟夫(Josef)说,莫妮卡(Monica

嗨,@ Josef。您应该尝试验证,name@xn--4ca9at.at因为此代码是关于验证而不是解释。如果您想添加一个punycode转换器,那么我很高兴在github.com/dominicsayers/isemail
Dominic Sayers

266

根据W3C HTML5规范

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

内容:

一个有效的电子邮件地址是该ABNF生产[...]相匹配的字符串。

注意:此要求是对RFC 5322故意违反RFC 5322定义了同时太严格(在“ @”字符之前),太模糊(在“ @”字符之后)和太松散(允许以大多数用户不熟悉的方式使用注释,空格字符和带引号的字符串)在此处实用。

以下与JavaScript和Perl兼容的正则表达式是上述定义的实现。

/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/


12
这是有趣的。这是对RFC的违反,但却是故意的,它使sesne变得更糟。实际示例:gmail忽略@之前的部分中的点,因此,如果您的电子邮件是test@gmail.com,则可以将电子邮件发送到test。@ gmail.com或test .... @ gmail.com,这两个地址都是根据RFC无效,但在现实世界中有效。
valentinas

我认为最后一部分应该是'+'而不是'*':^ [a-zA-Z0-9。!#$%&'* + / =?^ _`{|}〜-] + @ [a- zA-Z0-9-] +(?:\。[a-zA-Z0-9-] +)+ $
mmmmmm 2013年

7
@mmmmmm john.doe@localhost有效。当然,在现实世界中的应用程序(即社区)中,我希望您建议将*替换为+
rabudde

3
@valentinas实际上,RFC并不能排除这些地方的部分,但它们必须被引用。"test...."@gmail.com根据RFC是完全有效的,在语义上与test....@gmail.com
Rinke 2014年

如果尝试使用。@或.. @发送至我的公司的中继,则在尝试使用python发送电子邮件时收到错误消息。实际上,_ @也是如此。我宁愿在发送之前将其删除,也不愿相信收件人会这样做。
ndvo '16

201

在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

20
很想在Python中看到这一点
tdc

4
我认为只有addrspec一部分是与问题真正相关的。接受更多的内容并将其转发到系统中尚未准备好接受完整RFC5822地址的其他部分,就像开枪一样。
支石墓

3
不错(+1),但从技术上讲,它当然不是正则表达式...(这是不可能的,因为语法不规则)。
Rinke

10
正则表达式在一段时间前不再正常。这是一个有效的Perl'regex'!
rjh 2014年

4
我在IDEone上为此正则表达式设置了一个测试:ideone.com/2XFecH但是,“完全”是不公平的。有人会介意吗?我想念什么吗?
2014年

159

我用

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

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


28
!我的(建议不足)地址!@mydomain.net被拒绝。
Phrogz

3
根据此页面data.iana.org/TLD/tlds-alpha-by-domain.txt,没有顶级域名中只有单个字符的域,例如“ something.c”,“ something.a”,此处是该版本支持至少2个字符:“ something.pl”,“ something.us”:^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc 2015年

4
@韦恩·惠蒂 您遇到的主要问题是,是否要满足绝大多数地址或全部地址,包括除了测试电子邮件验证以外没有人使用的地址。
Patanjali

@TomaszSzulc您的答案中的额外反斜杠令人困惑,我刚刚对其进行了更正,并且支持2个字符的域名正在起作用,^ \ w +([-+。'] \ w +)* @ \ w +([-。] \ w +)* \。\ w {2,}([-。] \ w +)* $
Aqib Mumtaz

2
这失败了simon-@hotmail.com,实际上是有效的(我们的客户有类似的地址)`
Simon_Weaver

142

不知道最好的,但是这一次至少是正确的,只要在地址有他们的意见条用空格代替。

说真的 您应该使用已经编写的库来验证电子邮件。最好的方法可能只是将验证电子邮件发送到该地址。


2
据我所知,有些库也是错误的。我隐约记得,PHP PEAR有这样一个错误。
bortzmeyer

该页面的底部也有一个免责声明,涉及规范中的几件事。regexp不支持。
克里斯·韦斯特

7
那是RFC 822规范,而不是RFC 5322规范。
tchrist

12
最终,他是对的,真正验证电子邮件地址的唯一方法是向其发送电子邮件并等待回复。
Blazemonger,2011年

109

我想验证的电子邮件地址将由使用System.Net.Mail命名空间的ASP.NET Web应用程序使用,以将电子邮件发送给人员列表。因此,我没有尝试使用一些非常复杂的正则表达式,而是尝试从该地址创建一个MailAddress实例。如果地址格式不正确,则MailAddress构造函数将引发异常。这样,我知道我至少可以将电子邮件发送出去。当然,这是服务器端验证,但是至少您还是需要这样做。

protected void emailValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
    try
    {
        var a = new MailAddress(txtEmail.Text);
    }
    catch (Exception ex)
    {
        args.IsValid = false;
        emailValidator.ErrorMessage = "email: " + ex.Message;
    }
}

3
好点。即使此服务器验证拒绝了某个有效地址,也不会出现问题,因为无论如何您将无法使用此特定服务器技术发送到该地址。或者,您可以尝试使用您使用的任何第三方电子邮件库代替默认工具来执行相同的操作。
用户

我真的很喜欢这种方式如何利用.Net框架代码-重新发明轮子没有意义。太好了 简单,干净,并确保您可以实际发送电子邮件。做得好。
科里·豪斯

...是的,对于那些对如何进行验证感兴趣的人,可以查看Reflector中的代码-其中很多内容-而且它不是正则表达式!
汤姆·卡特

2
请注意:如果您仅想使用RFC5322进行验证(并且也不发送,在这种情况下,它就是如上所述的讨论点),则MailAddress类与RFC5322不匹配。请参阅:stackoverflow.com/questions/6023589/...
porges

只是一个小问题:如果要使服务器端验证程序代码更可重用(在这种情况下或一般而言),我建议使用args.Value而不是像txtEmail.Text硬编码一样引用该字段。后者将您的验证器绑定到单个控件实例,这可以,只要您具有单个电子邮件字段即可,但否则建议不要这样做。
pholpar '19

109

快速回答

使用以下正则表达式进行输入验证:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

此正则表达式匹配的地址:

  • 具有严格符合RFC 5321/5322的本地部分(即@符号前的部分),
  • 具有一个域部分(即@符号后的部分),该部分是主机名,带有至少两个标签,每个标签的长度最多为63个字符。

第二个约束是对RFC 5321/5322的限制。

详细回答

使用可识别电子邮件地址的正则表达式在各种情况下可能很有用:例如,扫描文档中的电子邮件地址,验证用户输入或作为数据存储库上的完整性约束。

但是,应注意,如果您要查找该地址是否实际指向现有邮箱,则没有替代方法可以向该地址发送消息。如果只想检查地址在语法上是否正确,则可以使用正则表达式,但是请注意,""@[]是一个语法正确的电子邮件地址,肯定没有引用现有的邮箱。

电子邮件地址的语法已在各种RFC中定义,最著名的是RFC 822 RFC 5322。RFC 822应该被视为“原始”标准,而RFC 5322应该被视为最新标准。RFC 822中定义的语法是最宽松的,随后的标准越来越多地限制了语法,在这种情况下,较新的系统或服务应识别过时的语法,但从不产生这种语法。

在此答案中,我将使用“电子邮件地址”来表示addr-specRFC中定义的含义(即jdoe@example.org,但不是"John Doe"<jdoe@example.org>,也不是some-group:jdoe@example.org,mrx@exampel.org;)。

将RFC语法转换为正则表达式存在一个问题:语法不规则!这是因为它们允许可无限嵌套的电子邮件地址中的可选注释,而无限嵌套不能用正则表达式描述。要扫描或验证包含注释的地址,您需要解析器或更强大的表达式。(请注意,像Perl这样的语言都具有以类似正则表达式的方式描述上下文无关语法的结构。)在此答案中,我将忽略注释,仅考虑适当的正则表达式。

RFC为电子邮件定义语法,而不是为电子邮件地址定义语法。地址可能出现在各种标题字段中,这是它们的主要定义位置。当它们出现在标题字段中时,地址可能包含(在词性标记之间)空格,注释,甚至换行符。但是在语义上这没有意义。通过从地址中删除此空格等,您可以获得语义上等效的规范表示。因此,的规范表示first. last (comment) @ [3.5.7.9]first.last@[3.5.7.9]

不同的语法应用于不同的目的。如果要扫描(可能是非常旧的)文档中的电子邮件地址,则最好使用RFC 822中定义的语法。另一方面,如果要验证用户输入,则可能需要使用RFC 5322中定义的语法,可能仅接受规范表示。您应该确定哪种语法适用于您的特定情况。

我在此答案中使用POSIX“扩展”正则表达式,假设使用ASCII兼容字符集。

RFC 822

我得出以下正则表达式。我邀请所有人尝试并打破它。如果您发现任何误报或误报,请在评论中发布它们,我将尝试尽快修复该表达式。

([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

我认为它完全符合包括勘误表在内的RFC 822。它仅识别规范形式的电子邮件地址。有关可识别(折叠)空格的正则表达式,请参见以下推导。

推导显示了我如何得出表达式。我列出了RFC中出现的所有相关语法规则,并按顺序列出了相应的正则表达式。在已发布勘误表的地方,我为校正后的语法规则提供了一个单独的表达式(标记为“勘误表”),并将更新的版本用作后续正则表达式中的子表达式。

如第3.1.4节所述。词法标记之间可以插入RFC 822的可选线性空格。在适当的地方,我已扩展表达式以适应此规则,并用“ opt-lwsp”标记结果。

CHAR        =  <any ASCII character>
            =~ .

CTL         =  <any ASCII control character and DEL>
            =~ [\x00-\x1F\x7F]

CR          =  <ASCII CR, carriage return>
            =~ \r

LF          =  <ASCII LF, linefeed>
            =~ \n

SPACE       =  <ASCII SP, space>
            =~  

HTAB        =  <ASCII HT, horizontal-tab>
            =~ \t

<">         =  <ASCII quote mark>
            =~ "

CRLF        =  CR LF
            =~ \r\n

LWSP-char   =  SPACE / HTAB
            =~ [ \t]

linear-white-space =  1*([CRLF] LWSP-char)
                   =~ ((\r\n)?[ \t])+

specials    =  "(" / ")" / "<" / ">" / "@" /  "," / ";" / ":" / "\" / <"> /  "." / "[" / "]"
            =~ [][()<>@,;:\\".]

quoted-pair =  "\" CHAR
            =~ \\.

qtext       =  <any CHAR excepting <">, "\" & CR, and including linear-white-space>
            =~ [^"\\\r]|((\r\n)?[ \t])+

dtext       =  <any CHAR excluding "[", "]", "\" & CR, & including linear-white-space>
            =~ [^][\\\r]|((\r\n)?[ \t])+

quoted-string  =  <"> *(qtext|quoted-pair) <">
               =~ "([^"\\\r]|((\r\n)?[ \t])|\\.)*"
(erratum)      =~ "(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-literal =  "[" *(dtext|quoted-pair) "]"
               =~ \[([^][\\\r]|((\r\n)?[ \t])|\\.)*]
(erratum)      =~ \[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

atom        =  1*<any CHAR except specials, SPACE and CTLs>
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+

word        =  atom / quoted-string
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-ref  =  atom

sub-domain  =  domain-ref / domain-literal
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

local-part  =  word *("." word)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*

domain      =  sub-domain *("." sub-domain)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*

addr-spec   =  local-part "@" domain
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*(\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*)*@((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(canonical) =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

RFC 5322

我得出以下正则表达式。我邀请所有人尝试并打破它。如果您发现任何误报或误报,请在评论中发布它们,我将尝试尽快修复该表达式。

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

我相信它完全符合包括勘误表在内的RFC 5322 。它仅识别规范形式的电子邮件地址。有关可识别(折叠)空格的正则表达式,请参见以下推导。

推导显示了我如何得出表达式。我列出了RFC中出现的所有相关语法规则,并按顺序列出了相应的正则表达式。对于包含语义上不相关的(折叠)空格的规则,我给出了一个单独的正则表达式,标记为“(规范化)”,不接受该空格。

我忽略了RFC中的所有“ obs-”规则。这意味着正则表达式仅匹配严格符合RFC 5322的电子邮件地址。如果必须匹配“旧”地址(如包含“ obs-”规则的较宽松的语法),则可以使用上一段中的RFC 822正则表达式之一。

VCHAR           =   %x21-7E
                =~  [!-~]

ALPHA           =   %x41-5A / %x61-7A
                =~  [A-Za-z]

DIGIT           =   %x30-39
                =~  [0-9]

HTAB            =   %x09
                =~  \t

CR              =   %x0D
                =~  \r

LF              =   %x0A
                =~  \n

SP              =   %x20
                =~  

DQUOTE          =   %x22
                =~  "

CRLF            =   CR LF
                =~  \r\n

WSP             =   SP / HTAB
                =~  [\t ]

quoted-pair     =   "\" (VCHAR / WSP)
                =~  \\[\t -~]

FWS             =   ([*WSP CRLF] 1*WSP)
                =~  ([\t ]*\r\n)?[\t ]+

ctext           =   %d33-39 / %d42-91 / %d93-126
                =~  []!-'*-[^-~]

("comment" is left out in the regex)
ccontent        =   ctext / quoted-pair / comment
                =~  []!-'*-[^-~]|(\\[\t -~])

(not regular)
comment         =   "(" *([FWS] ccontent) [FWS] ")"

(is equivalent to FWS when leaving out comments)
CFWS            =   (1*([FWS] comment) [FWS]) / FWS
                =~  ([\t ]*\r\n)?[\t ]+

atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
                =~  [-!#-'*+/-9=?A-Z^-~]

dot-atom-text   =   1*atext *("." 1*atext)
                =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

dot-atom        =   [CFWS] dot-atom-text [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

qtext           =   %d33 / %d35-91 / %d93-126
                =~  []!#-[^-~]

qcontent        =   qtext / quoted-pair
                =~  []!#-[^-~]|(\\[\t -~])

(erratum)
quoted-string   =   [CFWS] DQUOTE ((1*([FWS] qcontent) [FWS]) / FWS) DQUOTE [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  "([]!#-[^-~ \t]|(\\[\t -~]))+"

dtext           =   %d33-90 / %d94-126
                =~  [!-Z^-~]

domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  \[[\t -Z^-~]*]

local-part      =   dot-atom / quoted-string
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+"

domain          =   dot-atom / domain-literal
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*]

addr-spec       =   local-part "@" domain
                =~  ((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?)@((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?)
(normalized)    =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

请注意,某些来源(尤其是w3c)声称RFC 5322对本地部分(即@符号前的部分)过于严格。这是因为“ ..”,“ a..b”和“ a。” 是不是有效的点原子,而他们可以作为邮箱名。但是,RFC 确实允许像这样的本地部分,但必须引用它们。因此,而不是a..b@example.net您应该写"a..b"@example.net在语义上等效的。

进一步的限制

SMTP(如RFC 5321所定义)进一步限制了有效电子邮件地址(或实际上:邮箱名称)的集合。施加这种严格的语法似乎是合理的,以便匹配的电子邮件地址实际上可以用于发送电子邮件。

RFC 5321基本上保留了“本地”部分(即@符号前的部分),但对域部分(即@符号后的部分)进行了更严格的规定。它仅允许主机名代替点原子,并仅允许使用地址文本代替域文本。

当涉及到主机名和IP地址时,RFC 5321中提出的语法太宽容。我以这份草案RFC 1034为准则自由地“纠正”了有问题的规则。这是生成的正则表达式。

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

请注意,根据使用情况,您可能不希望在正则表达式中使用“常规地址字面量”。还要注意,我(?!IPv6:)在最终的正则表达式中使用了否定的前瞻,以防止“常规地址字面量”部分匹配格式错误的IPv6地址。某些正则表达式处理器不支持负前瞻。删除子字符串|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+如果要整个“常规地址字面量”部分,请从正则表达式中。

这是推导:

Let-dig         =   ALPHA / DIGIT
                =~  [0-9A-Za-z]

Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
                =~  [0-9A-Za-z-]*[0-9A-Za-z]

(regex is updated to make sure sub-domains are max. 63 charactes long - RFC 1034 section 3.5)
sub-domain      =   Let-dig [Ldh-str]
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?

Domain          =   sub-domain *("." sub-domain)
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*

Snum            =   1*3DIGIT
                =~  [0-9]{1,3}

(suggested replacement for "Snum")
ip4-octet       =   DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
                =~  25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]

IPv4-address-literal    =   Snum 3("."  Snum)
                        =~  [0-9]{1,3}(\.[0-9]{1,3}){3}

(suggested replacement for "IPv4-address-literal")
ip4-address     =   ip4-octet 3("." ip4-octet)
                =~  (25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement for "IPv6-hex")
ip6-h16         =   "0" / ( (%x49-57 / %x65-70 /%x97-102) 0*3(%x48-57 / %x65-70 /%x97-102) )
                =~  0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}

(not from RFC)
ls32            =   ip6-h16 ":" ip6-h16 / ip4-address
                =~  (0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement of "IPv6-addr")
ip6-address     =                                      6(ip6-h16 ":") ls32
                    /                             "::" 5(ip6-h16 ":") ls32
                    / [                 ip6-h16 ] "::" 4(ip6-h16 ":") ls32
                    / [ *1(ip6-h16 ":") ip6-h16 ] "::" 3(ip6-h16 ":") ls32
                    / [ *2(ip6-h16 ":") ip6-h16 ] "::" 2(ip6-h16 ":") ls32
                    / [ *3(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16 ":"  ls32
                    / [ *4(ip6-h16 ":") ip6-h16 ] "::"                ls32
                    / [ *5(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16
                    / [ *6(ip6-h16 ":") ip6-h16 ] "::"
                =~  (((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::

IPv6-address-literal    =   "IPv6:" ip6-address
                        =~  IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)

Standardized-tag        =   Ldh-str
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]

dcontent        =   %d33-90 / %d94-126
                =~  [!-Z^-~]

General-address-literal =   Standardized-tag ":" 1*dcontent
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+

address-literal =   "[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]"
                =~  \[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)]

Mailbox         =   Local-part "@" ( Domain / address-literal )
                =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

用户输入验证

常见的用例是用户输入验证,例如在html表单上。在这种情况下,排除地址文字并在主机名中至少需要两个标签通常是合理的。以上一节中改进的RFC 5321正则表达式为基础,结果表达式为:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

我不建议进一步限制本地部分,例如通过排除带引号的字符串,因为我们不知道某些主机允许哪种邮箱名称(例如"a..b"@example.net或什至"a b"@example.net)。

我也不建议针对文字顶级域列表进行显式验证,甚至不施加长度限制(请记住“ .museum”如何无效[a-z]{2,4}),但是如果您必须执行以下操作:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?\.)*(net|org|com|info|等等...)

如果您决定采用显式顶级域验证的方法,请确保使正则表达式保持最新。

进一步的考虑

当仅在域部分(@符号后)接受主机名时,上述正则表达式将只接受最多包含63个字符的标签。但是,他们并没有强制要求整个主机名的长度最多为253个字符(包括点)。尽管从严格意义上说,此约束仍然是常规的,但制作包含此规则的正则表达式是不可行的。

另一个考虑因素是反馈给用户,尤其是在使用正则表达式进行输入验证时。如果用户输入了错误的地址,那么比简单的“语法上错误的地址”给出更多的反馈会更好。使用“香草”正则表达式是不可能的。

这两个考虑因素可以通过解析地址来解决。在某些情况下,还可以通过使用检查它的额外正则表达式来解决主机名上的额外长度约束,并针对两个表达式匹配地址。

此答案中的任何正则表达式均未针对性能进行优化。如果性能是一个问题,则应查看是否可以(以及如何)优化所选的正则表达式。


3
RFC 6532更新了5322,以允许并包括完整的,干净的UTF-8。其他详细信息在这里

根据Wikipedia的说法,本地部分在加点时,每个部分的限制为64个字符,并且RFC 5322还引用了点的本地部分,但要受域的限制。例如arbitrary-long-email-address-should-be-invalid-arbitrary-long-email-address-should-be-invalid.and-the-second-group-also-should-not-be-so-long-and-the-second-group-also-should-not-be-so-long@example.com不应该验证。我建议将第一组(在可选点之前的名称)和第二组(在以下点之后的名称)中的“ +”符号更改为{1,64}
Xavi Montero,2017年

由于注释的大小受限制,因此这是我计划使用的结果正则表达式,它是此答案开头的内容,加上限制本地部分的大小,以及在“ /”之前添加反斜杠。 PHP以及regex101.com中都需要的符号:在PHP中,我使用:$emailRegex = '/^([-!#-\'*+\/-9=?A-Z^-~]{1,64}(\.[-!#-\'*+\/-9=?A-Z^-~]{1,64})*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+$/';
Xavi Montero

注意:由于某些原因,从渲染的markdown复制时,StackOverflow会添加隐藏字符。将其复制到regex101.com,您将在其中看到黑点。您必须删除它们并更正字符串。如果将其集成到答案中,则可以正确复制它们。抱歉给你带来不便。我不想添加一个新答案,因为这是正确的答案。另外,除非社区认为应该将其集成到其中,否则我不想直接进行编辑。
哈维·蒙特罗

@XaviMontero Thaks为Xavi贡献了力量!您是否有对RFC的引用,指出本地零件标签上的64个字符限制?如果是这样,我很乐意调整答案。
Rinke

73

网上有很多这样的例子(我想即使是一个完全验证RFC的例子-但是如果有内存的话,它可能需要数十/数百行)。人们倾向于验证这种事情。为什么不检查它是否包含@以及至少一个。并满足一些简单的最小长度。输入伪造的电子邮件并且仍然匹配任何有效的正则表达式都是很简单的。我猜想误报要比误报好。


1
是的,但是哪个 RFC?:)这个[RFC‐5322–validator](stackoverflow.com/questions/201323/…)大约只有40行。
tchrist 2010年

14
一个 。不需要。TLD可以有电子邮件地址,也可以有IPv6地址
Sijmen Mulder

1
RFC并非故事的结局:ICANN不再允许“无点”域名:icann.org/news/announcement-2013-08-30-en
Synchro

64

在确定允许使用哪些字符时,请记住您的撇号和连字符的朋友。我无法控制我的公司使用来自HR系统的姓名生成我的电子邮件地址的事实。其中包括我姓氏的撇号。我无法告诉您我的电子邮件地址为“无效”的事实使我被阻止与网站互动的次数。


4
这在程序中非常常见的问题,这些程序对人名中的允许和不允许进行了无端假设。一个人不应该做这样的假设,只接受相关RFC所说的任何字符。
tchrist

4
是。我特别激怒程序员拒绝电子邮件地址中的大写字母!傻和/或懒。
PhiLho 2012年

63

该正则表达式来自Perl的Email :: Valid库。我相信它是最准确的,它可以匹配所有822。而且,它基于O'Reilly书中的正则表达式:

使用Jeffrey Friedl在精通正则表达式http://www.ora.com/catalog/regexp/)中的示例构建的 正则表达式

$RFC822PAT = <<'EOF';
[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\x
ff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\
x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?!
[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]
)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\
x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
40)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\
\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
)]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-
\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\
000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\
]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
)[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<
>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
*\)[\040\t]*)*)*>)
EOF

14
O_O您还需要成为正则表达式大师才能了解它在做什么
Chris McGrath 2013年

45

当您使用PHP编写代码时,建议您对电子邮件使用PHP内置验证。

filter_var($value, FILTER_VALIDATE_EMAIL)

如果您运行的PHP版本低于5.3.6,请注意以下问题:https : //bugs.php.net/bug.php?id=53091

如果您想了解更多信息,请参见此处:PHP的filter_var FILTER_VALIDATE_EMAIL是否真正起作用?


得到表决,这正是我要说的。不处理IDN,而是事先转换为少量代码即可解决此问题。PHP> = 5.3具有idn_to_ascii()。验证电子邮件的最佳和最简便的方法之一。
泰勒


42

我从不用自己的正则表达式进行创建,因为其他人可能已经提出了更好的版本。我总是使用regexlib找到自己喜欢的一个。


1
标记了它的长度和内容,但它以41票仍然是一个不错的贡献,不应删除。
威尔

37

没有一个真正可用的。
我在回答“是否有用于验证电子邮件地址的php库”的答案中讨论了一些问题,也很难Regexp邮件地址识别中讨论吗?

简而言之,不要指望一个可用的正则表达式能正确完成工作。最好的正则表达式将验证语法,而不是电子邮件的有效性(jhohn@example.com是正确的,但可能会反弹...)。


如果我错了,请纠正我,但我相信PHP使用PCRE模式。如果是这样,您应该能够制作类似于Abigail的RFC 5322模式的内容
tchrist

@tchrist:不确定PCRE是否已赶上这种语法(我发现)。如果是这样,则不确定PHP的PCRE是否赶上了该版本的PCRE ...好吧,如果我正确理解了该语法,那么无论如何,您也可以使用PEG解析器,它比正则表达式更加清晰和完整。
PhiLho

PCRE 已经赶上它,但也许PHP尚未与PCRE赶上。☹
tchrist

36

一个至少不会拒绝任何有效电子邮件地址的简单正则表达式将检查某项内容,然后是@符号,然后是某些内容,然后是句点和至少2个内容。它不会拒绝任何邮件,但是在查看规范后,我找不到任何有效且被拒绝的电子邮件。

电子邮件=〜 /.+@[^@]+\.[^@]{2,}$/


3
这就是我想要的。不是很严格,但是请确保只有1 @(因为我们正在解析列表,并希望确保没有丢失的逗号)。仅供参考,如果在引号中包含@,则可以在其左侧添加一个@:Valid_email_addresses,但它的边缘很漂亮。
乔什(Josh)

2
使用它之后,意识到它并没有完全起作用。 /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ 实际上检查1 @符号。您的正则表达式会因为。*结尾而让多个字符通过。
乔什(Josh)

1
对。我不是要拒绝所有无效的邮件,只是要拒绝拒绝有效的电子邮件地址。
spig 2011年

1
最好使用此方法:/^[^@]+@[^@]+\.[^@]{2,4}$/确保它以2到4个非@字符结尾。正如@Josh指出的那样,它现在最后允许一个额外的@。但您也可以将其更改为:/^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/由于所有顶级域都是aZ字符。您可以替换45以上允许顶级域名将不再在未来也是如此。
FLY 2013年

@ FLY,ka @ foo。返回正确。按照标准,应该吗?
SexyBeast

29

您可以使用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

这似乎做得很好。它允许:a-b'c_d.e@f-g.h但是能够捕捉到不适当的变化,例如a-b'c_d.@f-g.ha-b'c_d.e@f-.h
dsdsdsdsd 2014年

25

有关验证电子邮件地址的最佳正则表达式的最全面评估,请参阅此链接;“ 比较验证正则表达式的电子邮件地址

这是当前的顶级表达式,仅供参考:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i

Spoon16:该链接不是真的正确。它声称没有完美的模式来验证电子邮件地址的说法显然是错误的。你可以,但你必须确保你遵循RFC降权落到实处。而且,您还必须选择正确的RFC。
tchrist 2010年

现在,“ best”不适用于java regex-即使在正确转义和转换字符串之后也是如此。
埃里克·陈

23

更不用说在不久的将来允许使用非拉丁(中文,阿拉伯文,希腊文,希伯来文,西里尔文等)域名。每个人都必须更改所使用的电子邮件正则表达式,因为这些字符肯定不会被[a-z]/i也不覆盖。\w。他们都会失败。

毕竟,验证电子邮件地址的最佳方法仍然是实际发送电子邮件到该地址以验证该地址。如果电子邮件地址是用户身份验证的一部分(注册/登录/等),则可以将其与用户激活系统完美结合。即,发送带有链接的电子邮件,该链接具有指向指定电子邮件地址的唯一激活密钥,并且仅当用户使用电子邮件中的链接激活了新创建的帐户时才允许登录。

如果正则表达式的目的只是为了快速在用户界面中通知用户指定的电子邮件地址看起来格式不正确,那么最好还是检查它是否与以下正则表达式基本匹配:

^([^.@]+)(\.[^.@]+)*@([^.@]+\.)+([^.@]+)$

就那么简单。为什么您会关心名称和域中使用的字符?输入有效的电子邮件地址(而不是服务器的地址)是客户的责任。即使客户输入语法上有效的电子邮件地址(如)aa@bb.cc,也不能保证它是合法的电子邮件地址。没有一个正则表达式可以解决这一问题。


4
我同意发送身份验证消息通常是处理此类问题的最佳方法,语法正确和有效并不相同。当我被要求为“确认”键入两次电子邮件地址时,我感到沮丧,好像无法查看自己键入的内容一样。无论如何,我只将第一个复制到第二个,似乎越来越多地被使用。
PeteT

同意!但是我认为这个正则表达式是无效的,因为它允许spaces@.eg之后。test@test.ca com net被视为使用上述正则表达式的有效电子邮件,因为它应该返回无效。
CB4

20

HTML5规范提出用于验证电子邮件地址的简单的regex:

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

这故意不符合RFC 5322

注意:此要求是对RFC 5322故意违反,它定义了同时太严格(在字符之前),太模糊(在字符之后)和太松散(允许注释,空白字符,并以大多数用户不熟悉的方式引用字符串)在此处具有实际用途。@@

根据RFC 3696勘误表1690,总长度也可以限制为254个字符。


最佳答案!这是w3建议的链接:w3.org/TR/html5/forms.html#valid-e-mail-address 许多浏览器都采用此正则表达式。
瑞安·泰勒

3
这不是最好的答案!此模式与以下完全无效的地址匹配:invalid@emailaddress。在使用它之前,我强烈要求谨慎并进行大量测试!
谢里登

@Sheridan,如果您认为HTML5规范存在问题,则可以在此处提出问题:github.com/w3c/html/issues
Luna,

这不会在stackoverflow.com/a/8829363上增加太多,并且恕我直言,对其进行编辑或评论会更好。

example @ localhost是有效的,但是对于实际应用程序,您可能需要强制执行域扩展,您所需要做的就是将最终的*更改为+以实现此目的(将模式的该部分从0+更改为1+ )
米奇·斯奇威尔

15

对于生动的演示,以下怪物非常好,但仍不能正确识别所有语法上有效的电子邮件地址:它最多可以识别四个级别的嵌套注释。

这是解析器的工作,但是即使地址在语法上是有效的,它仍可能无法传递。有时,您必须诉诸乡巴佬的方法:“嘿,大家,看ee-us!”

// derivative of work with the following copyright and license:
// Copyright (c) 2004 Casey West.  All rights reserved.
// This module is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself.

// see http://search.cpan.org/~cwest/Email-Address-1.80/

private static string gibberish = @"
(?-xism:(?:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<DQ>(?-xism:(?-xism:[
^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D])))+<DQ>(?-xism:(?-xi
sm:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xis
m:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\
s*)+|\s+)*))+)?(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?
-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<(?-xism:(?-xi
sm:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^(
)\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(
?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))
|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<
>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]
+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:
(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s
*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xi
sm:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*
<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D]
)))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-x
ism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+
)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:(
?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?
-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s
*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(
?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)
+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-x
ism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-xi
sm:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:
\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+
)*\s*\)\s*)+|\s+)*)))>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-
xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))|(?-xism:(?-x
ism:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*
(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D])
)|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()
<>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s
]+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism
:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\
s*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-x
ism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)
*<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D
])))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-
xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)
+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:
(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(
?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[
^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\
s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+
(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism
:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:
[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+
))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*
)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism
:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\(
(?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A
\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-
xism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-x
ism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism
:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))
+)*\s*\)\s*)+|\s+)*))))(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?
>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:
\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0
D]))|)+)*\s*\)\s*))+)*\s*\)\s*)*)"
  .Replace("<DQ>", "\"")
  .Replace("\t", "")
  .Replace(" ", "")
  .Replace("\r", "")
  .Replace("\n", "");

private static Regex mailbox =
  new Regex(gibberish, RegexOptions.ExplicitCapture); 

12

根据官方标准RFC 2822,有效的电子邮件正则表达式为

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

如果您想在Java中使用它,则非常简单

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "xyz@hotmail.com";

      //Set the email pattern string
      Pattern p = Pattern.compile(" (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"
              +"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")"
                     + "@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\]");

      //Match the given string with the pattern
      Matcher m = p.matcher(email);

      //check whether match is found 
      boolean matchFound = m.matches();

      if (matchFound)
        System.out.println("Valid Email Id.");
      else
        System.out.println("Invalid Email Id.");
   }
}

1
您的正则表达式不包含第一个大写字母,例如Leonardo.davinci@gmail.com,这对于某些用户而言可能很烦人。请改用此选项:(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Kebab Krabby

@KebabKrabby谢谢,请编辑答案,我接受更改。
AZ_

如果我将更改添加到您的答案中,它将不再是RFC 2822,所以我不知道这是否正确。
Kebab Krabby

11

这是我使用的PHP。我本着“错误肯定胜于错误否定”的精神选择了此解决方案,正如在这里的另一位评论者所声明的那样,并且为了保持响应时间延长和服务器负载减少……实际上,不需要浪费服务器资源。一个正则表达式,当它可以消除最简单的用户错误时。如果需要,您始终可以通过发送测试电子邮件来跟进。

function validateEmail($email) {
  return (bool) stripos($email,'@');
}

1
a)“浪费的服务器资源”是无限的,但是如果您愿意,可以用JS在客户端进行处理。b)您需要发送什么注册邮件,并且用户输入me @ forgotthedotcom?您的“解决方案”失败了,您失去了一个用户。
johnjohn

a)依赖JS验证会在禁用JavaScript时失败,这也不是最好的主意(只是顺便说一句)
auco 2013年

11

RFC 5322标准:

允许点原子本地部分,带引号的字符串本地部分,过时的(混合的点原子和带引号的字符串)本地部分,域名域,(IPv4,IPv6和IPv4映射的IPv6地址)域文字域,和(嵌套的)CFWS。

'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD'

RFC 5321标准:

允许点原子本地部分,带引号的字符串本地部分,域名域以及(IPv4,IPv6和IPv4映射的IPv6地址)域文字域。

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!"?(?>\\\[ -~]|[^"]){65,}"?@)(?>([!#-\'*+\/-9=?^-~-]+)(?>\.(?1))*|"(?>[ !#-\[\]-~]|\\\[ -~])*")@(?!.*[^.]{64,})(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?2)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?))|(?>(?>IPv6:(?>(?3)(?>:(?3)){5}:|(?!(?:.*[a-f0-9]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?6)){3}))\])$/iD'

基本:

允许点原子本地部分和域名域(要求至少两个域名标签的TLD限制为2-6个字母字符)。

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"

那是什么恶魔语言?我看到一个/D标志,并且您已经用单引号将其引号,但还使用斜杠来分隔该模式?不是Perl,也不能是PCRE。因此是PHP吗?我相信这是允许递归的唯一三个(?1)
tchrist

在PHP中,它使用PCRE。斜杠仅用于分隔特殊字符,例如括号,方括号,当然还有斜杠和单引号。/ D标志(如果您不知道)是为了防止在字符串的末尾添加换行符,否则将允许该行。
MichaelRushton

9

奇怪的是,您“不能”允许4个字符的TLD。您正在禁止人们使用.info.name,并且长度限制会阻止.travel.museum,但是是的,它们不如2个字符的TLD和3个字符的TLD常见。

您也应该允许使用大写字母。电子邮件系统将规范本地部分和域部分。

对于域名的正则表达式,域名不能以“-”开头,也不能以“-”结尾。短跑只能停留在两者之间。

如果您使用了PEAR库,请检查其邮件功能(忘记确切的名称/库)。您可以通过调用一个函数来验证电子邮件地址,然后根据RFC822中的定义来验证电子邮件地址。


2
@Joseph Yee:RFC 822有点过时吗?
tchrist

8
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;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.