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

4125
多年来,我已经逐渐开发出一种正则表达式,可以正确验证大多数电子邮件地址(假设它们没有使用IP地址作为服务器部分)。我在几个PHP程序中使用它,大多数情况下都有效。但是,不时有人联系我,称使用该表达式的站点出现问题,我最近意识到我没有允许四个字符的TLDs,因此不得不进行一些调整。你认为验证电子邮件的最佳正则表达式是什么?我看过几种解决方案,它们使用函数,这些函数使用几个较短的表达式,但我宁愿在一个简单的函数中使用一个长且复杂的表达式,而不是在一个更复杂的函数中使用几个短的表达式。

10
可以验证 IDNA 格式是否正确的正则表达式太长了,无法在 StackExchange 中使用。(规范化的规则非常复杂,特别不适合使用正则表达式处理。) - Jasen
正则表达式可能是可变的,因为在某些情况下,电子邮件内容可能包含空格,而在其他情况下,则不能包含任何空格。 - Ṃųỻịgǻňạcểơửṩ
我建议您查看这篇文章:https://debounce.io/blog/articles/email-syntax-error-explained/ - Iman
显示剩余7条评论
80个回答

4

没有人提到本地化(i18n)的问题。如果你的客户来自世界各地,该怎么办呢?

你需要根据每个国家/地区对正则表达式进行细分,我曾经见过开发人员建立一个大型字典或配置。检测用户的浏览器语言设置可能是一个很好的起点。


4
我们已经使用http://www.aspnetmx.com/几年了,取得了一定的成功。您可以选择您想要验证的级别(例如:语法检查,检查域名,MX记录或实际电子邮件)。
对于前端表单,我们通常验证域名是否存在和语法是否正确,然后进行更严格的验证以清除我们的数据库,然后再进行批量邮件发送。

链接已经失效(超时)-“无法连接。在连接到www.aspnetmx.com期间发生错误。” - Peter Mortensen
这个问题最初是在2008年回答的。时间过的真快啊... - cbp

4
根据RFC 2821RFC 2822,电子邮件地址的本地部分可以使用以下任意ASCII字符:
  1. 大写字母和小写字母
  2. 数字0到9
  3. 字符! # $%&'*+-/ =? ^_` {|}~
  4. 字符“.”, 前提是它不是本地部分中的第一个或最后一个字符。
匹配:
  • a&d@somedomain.com
  • a*d@somedomain.com
  • a/d@somedomain.com

不匹配:

  • .abc@somedomain.com
  • abc.@somedomain.com
  • a>b@somedomain.com

如果符合RFC 2821和2822标准,您可以使用以下内容:

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

电子邮件 - 符合RFC 2821、2822标准


为什么它不能在Håkan.Söderström@malmö.se上运行? - Cees Timmerman

4
我通常使用以下正则表达式来验证电子邮件地址。它涵盖了基于英语字符的所有电子邮件地址格式。
"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";

以下是C#示例:
添加程序集引用:
using System.Text.RegularExpressions;

并使用下面的方法传递电子邮件地址并返回布尔值
private bool IsValidEmail(string email) {
    bool isValid = false;
    const string pattern = @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";

    isValid = email != "" && Regex.IsMatch(email, pattern);

    // Same above approach in multiple lines
    //
    //if (!email) {
    //    isValid = false;
    //} else {
    //    // email param contains a value; Pass it to the isMatch method
    //    isValid = Regex.IsMatch(email, pattern);
    //}
    return isValid;
}

该方法用于验证传入参数中的电子邮件字符串。 当参数为null、空字符串、undefined或参数值不是有效的电子邮件地址时,它将返回false。 只有当参数包含有效的电子邮件地址字符串时,它才会返回true。


2
这段代码能够接受 "Håkan.Söderström@malmö.se" 或者 "试@例子.测试.مثال.آزمایشی" 邮箱吗? - Ivan Z
3
这是针对标准电子邮件服务器和标准字符的。如果涉及非英语语言,就需要自行定制正则表达式。 - Suhaib Janjua
正则表达式和电子邮件规范包括UTF-8,因此无逻辑的响应。 - rob2d
1
它是最好的正则表达式的哪个方面?最全面的?最简单的?假阴性最少的?假阳性最少的?最快的?在实际的现实世界使用中,用户投诉最少的?这些属性的某种组合?还是其他什么?请通过编辑(更改)您的答案来回答,而不是在评论中回答(不要包含“Edit:”、“Update:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen

4
我看过的每个正则表达式,包括一些由Microsoft使用的,都不会允许通过下面这个合法电子邮件地址:simon-@hotmail.com 我曾经遇到一个真实客户的电子邮件地址就是这种格式,他无法下订单。
以下是我的解决方案:
  • 一个最小化的正则表达式,不会出现假负数。或者使用 MailAddress 构造函数进行额外的检查(见下文):
  • 检查常见的拼写错误.cmo.gmial.com并要求确认"Are you sure this is your correct email address. It looks like there may be a mistake." 如果用户确��输入正确,则允许用户接受所输内容。
  • 在电子邮件实际发送时处理退信,并手动验证它们以检查明显的错误。
try
{
    var email = new MailAddress(str);

    if (email.Host.EndsWith(".cmo"))
    {
        return EmailValidation.PossibleTypo;
    }

    if (!email.Host.EndsWith(".") && email.Host.Contains("."))
    {
        return EmailValidation.OK;
    }
}
catch
{
    return EmailValidation.Invalid;
}

1
这个回答有误导性,并且与问题无关。允许用户输入错误的电子邮件是一种商业决策,问题是关于使用正则表达式进行验证。 - Kerem Demirer
1
这篇帖子的第一个答案可以很好地通过 simon-@hotmail.com - Michael Sims
什么编程语言?C#Java?还是其他的? - Peter Mortensen
.gmial.com” 的示例不在示例代码中。 - Peter Mortensen
我从未见过将“Gmail”拼错为“Gmial”的情况。 - Peter Mortensen

4
尽管已经有非常详细的答案,但我认为这对于只想查找Java中简单的验证电子邮件地址方法或从字符串中获取所有电子邮件地址的开发人员来说仍然太复杂了。
public static boolean isEmailValid(@NonNull String email) {
    return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}

就正则表达式而言,我总是使用这个正则表达式来解决我的问题。

"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}"

如果你想通过匹配电子邮件正则表达式从字符串中找到所有的电子邮件地址。你可以在这个链接找到一个方法。


“which works for my problems.”的意思是“适用于我的问题”。那么这些问题会是什么呢?有哪些假阳性和假阴性的示例?如何处理它们? - Peter Mortensen
什么编程语言?Java?这是第二个评论和问题。 - Peter Mortensen

3
以下是验证电子邮件地址的正则表达式:

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

^.+@\w+(\.\w+)+$

鉴于之前的所有答案,这样一个简单的正则表达式需要解释(例如,为什么之前的庞大复杂性是必要的?)。它有什么属性?它失败了什么?它能成功应用的一些例子是什么?它无法工作的一些例子是什么?请通过[编辑(更改)您的答案]来回复,而不是在评论中回复(不要包含"Edit:"、"Update:"或类似内容 - 答案应该看起来像是今天编写的)。 - Peter Mortensen

3

这是我建立的一个版本。它不是万无一失的,但它很“简单”且几乎检查了所有内容。

[\w+-]+(?:\.[\w+-]+)*@[\w+-]+(?:\.[\w+-]+)*(?:\.[a-zA-Z]{2,4})

我认为有必要解释一下,以便您在需要时进行修改:

(e) [\w+-]+ 匹配至少一次a-z、A-Z、_、+、-。

(m) (?:\.[\w+-]+)* 匹配以点(.)开头,后面跟零个或多个a-z、A-Z、_、+、-

@ = @

(i) [\w+-]+ 匹配至少一次a-z、A-Z、_、+、-。

(l) (?:\.[\w+-]+)* 匹配以点(.)开头,后面跟零个或多个a-z、A-Z、_、+、-

(com) (?:\.[a-zA-Z]{2,4}) 匹配以点(.)开头,后面跟2到4个a-z、A-Z的字符。

得出的结果为 e(.m)@i(.l).com,其中 (.m)(.l) 是可选的,也可以重复多次。

我认为这个正则表达式可以验证所有有效的电子邮件地址,但不使用过于复杂的正则表达式来阻止潜在的无效电子邮件地址,在大多数情况下也不需要这样做。

请注意,这将允许 +@-.com,但这是为了保持简单而做出的妥协。


и°ўи°ўпјҒиҝҷеҜ№жҲ‘жңүз”ЁгҖӮд»ҘдёӢжҳҜдҪҝз”ЁQt5жөӢиҜ•иҝҮзҡ„C/C++иҪ¬д№үзүҲжң¬пјҡQRegExp rx("[\w+-]+(?:\.[\w+-]+)@[\w+-]+(?:\.[\w+-]+)(?:\.[a-zA-Z]{2,})"); - Mr. Developerdude

3
我有类似的愿望:希望在不过度检查语法的情况下快速检查电子邮件地址(Mail::RFC822::Address 的答案显然是正确的),用于 电子邮件发送实用程序。我选择了这个(我是一个 POSIX 正则表达式人,所以我通常不使用来自 PCRE\d 等,因为它们让事情对我来说不太可读):
preg_match("_^[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*@[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])?)*\$_", $adr)

这是符合RFC标准的,但它明确排除了过时的形式以及直接IP地址(IP地址和遗留IP地址),而那个实用程序的目标群体中的某些人(主要是:在IRC上打扰我们的人)通常不需要或不想要这些。
国际化域名(IDNs)明确地不在电子邮件范围内:像“foo@cäcilienchor-bonn.de”这样的地址必须写成“foo@xn--ccilienchor-bonn-vnb.de”传输(包括HTML中的链接等),只有GUI允许显示(并接受转换)这些名称到用户(从用户)。

关于“传统IP地址”:您是指“IPv4 IP地址”吗? - Peter Mortensen
@PeterMortensen:(感谢您的语法突出显示和英文修正,但现在似乎有些问题,它说社区维基与您作为作者?)是的,传统IP地址是IPv4地址几年来一直被称为IP地址是IPv6地址。 - mirabilos

3
这个问题发布的正则表达式现在已经过时了,因为新的通用顶级域名(gTLD)即将到来(例如.london,.basketball,. 通販)。要验证电子邮件地址,有两个答案(这对绝大多数人都是相关的)。
  1. 就像主答案所说的那样-不使用正则表达式。只需通过向地址发送电子邮件来验证它(捕获无效地址的异常)
  2. 使用非常通用的正则表达式,至少确保它们使用类似{something}@{something}.{something}的电子邮件结构。没有必要使用详细的正则表达式,因为您将无法全部捕获,并且几年后会有一批新的数据,您将不得不再次更新正则表达式。

我决定使用正则表达式,因为不幸的是,一些用户不阅读表格并将错误的数据放入错误的字段中。当他们尝试将不是电子邮件的内容放入电子邮件输入字段时,这将至少提醒他们,并应该节省您处理有关电子邮件问题的时间。

(.+)@(.+){2,}\.(.+){2,}

gTLD和TLD有什么区别? - Peter Mortensen
它们实际上都是一样的,只是分类不同。主要有国家代码顶级域名(ccTLD),例如.co.uk或.fr。这些分配给每个国家,并作为搜索引擎理解位置/目标受众的因素。 赞助的顶级域名(sTLD)分配给组织或政府,例如.gov。 通用顶级域名(gTLD)涵盖通用扩展名,例如.com、.london、.mail等。对可使用的扩展名有一些限制,价格可能会有很大差异,但Google也表示,无论您使用.com还是其他扩展名,都不太重要。 - McGaz

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