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

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

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

2

Java Mail API为我们创造了魔法。

try
{
    InternetAddress internetAddress = new InternetAddress(email);
    internetAddress.validate();
    return true;
}
catch(Exception ex)
{
    return false;
}

我从这里获取了这个内容。


1
Java Mail API是Java SE平台可选的包,也包含在Java EE平台中。 - Developer Marius Žilėnas

1

我发现了一篇不错的文章, 文章中表示验证电子邮件地址的最佳方法是使用正则表达式/.+@.+\..+/i


4
不匹配有效地址,例如:me@localhost - Toto
3
它也会匹配无效的电子邮件地址,比如john doe@his domain.com。 - chukko

1
正如之前所提到的,你不能用正则表达式验证电子邮件。然而,以下是我们目前使用的内容来确保用户输入不是完全虚假的(忘记了TLD等等)。
这个正则表达式将允许在@符号之前和之后使用IDN域名和特殊字符(如Umlauts)。
/^[\w.+-_]+@[^.][\w.-]*\.[\w-]{2,63}$/iu

使用哪种正则表达式语言和/或编程语言?Perl?还是其他的? - Peter Mortensen

1

我想提出我的方法,它相对简单,同时确保电子邮件结构正确并限制禁止使用的字符。适用于拉丁字符。

/^(?![\w\.@]*\.\.)(?![\w\.@]*\.@)(?![\w\.]*@\.)\w+[\w\.]*@[\w\.]+\.\w{2,}$/

到目前为止,这是最好的一个。 - Epic Speedy
你能用Golang来做这件事吗? - San

1

我将代码转换为Java以匹配编译器:

String pattern = "(?:[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-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-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-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";

1

全球最流行的博客平台 WordPress 使用此函数来验证电子邮件地址...

但是他们使用多个步骤来完成此操作。

当您使用此函数中提到的正则表达式时,无需再担心了...

以下是该函数:

/**
 * Verifies that an email is valid.
 *
 * Does not grok i18n domains. Not RFC compliant.
 *
 * @since 0.71
 *
 * @param string $email Email address to verify.
 * @param boolean $deprecated Deprecated.
 * @return string|bool Either false or the valid email address.
 */
function is_email( $email, $deprecated = false ) {
    if ( ! empty( $deprecated ) )
        _deprecated_argument( __FUNCTION__, '3.0' );

    // Test for the minimum length the email can be
    if ( strlen( $email ) < 3 ) {
        return apply_filters( 'is_email', false, $email, 'email_too_short' );
    }

    // Test for an @ character after the first position
    if ( strpos( $email, '@', 1 ) === false ) {
        return apply_filters( 'is_email', false, $email, 'email_no_at' );
    }

    // Split out the local and domain parts
    list( $local, $domain ) = explode( '@', $email, 2 );

    // LOCAL PART
    // Test for invalid characters
    if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
        return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
    }

    // DOMAIN PART
    // Test for sequences of periods
    if ( preg_match( '/\.{2,}/', $domain ) ) {
        return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
    }

    // Test for leading and trailing periods and whitespace
    if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
        return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
    }

    // Split the domain into subs
    $subs = explode( '.', $domain );

    // Assume the domain will have at least two subs
    if ( 2 > count( $subs ) ) {
        return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
    }

    // Loop through each sub
    foreach ( $subs as $sub ) {
        // Test for leading and trailing hyphens and whitespace
        if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
            return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
        }

        // Test for invalid characters
        if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
            return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
        }
    }

    // Congratulations your email made it!
    return apply_filters( 'is_email', $email, $email, null );
}

这太过严格了,它不允许引用用户组件,并且不支持国际化电子邮件地址。此外,_deprecated_argument 函数未定义。 - awwright

0

我们还有另一种选择,可以使用 DataAnnotations,它具有一个 EmailAddressAttribute。这不仅可以应用于类的属性,还可以在运行时利用。

using System.ComponentModel.DataAnnotations;

典型用法

public class Person
{
    public int Id { get; set; }

    [EmailAddress]
    public string Email { get; set; }
}

在运行时

var emailAddressAttribute = new EmailAddressAttribute();

if (emailAddressAttribute.IsValid("name@email.com"))
{
    //email is valid
}
else
{
    //email is invalid
}

0

针对我的需求,如果提供了显示名称,我需要一种方法来提取它。
感谢其他答案和https://emailregex.com/上提供的正则表达式,我想出了以下解决方案:

/^(?:([^<]*?)\s*<)?((?:[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])+)\]))>?$/gi

这个匹配包括显示名称(第一组) + 电子邮件地址(第二组)

匹配示例:

john.doe@example.com
john.o'doe@example.com
John <john@doe.com>
<john@doe.com>
This is <john@127.0.0.1>

已使用https://regex101.com/ 进行测试

当然,正如其他答案中提到的那样,还需要对显示名称和电子邮件地址的长度进行额外验证(不应超过320个UTF-8字节)。


0
问题标题相当通用,但问题正文表明它是关于基于PHP的解决方案的。将尝试回答两者。
一般而言,对于所有编程语言: 通常,使用正则表达式“验证”电子邮件地址是任何基于互联网的服务提供商都应该避免的事情。在域名和电子邮件地址类型方面的可能性已经增加了很多,任何未经深思熟虑的验证尝试都可能导致拒绝一些有效用户进入您的系统。为了避免这种情况,最好的方法之一是向用户发送电子邮件并验证其接收情况。 "Universal Acceptance Steering Group" 的好人们已经编译了按语言分类的库列表,这些库被发现符合/不符合涉及验证的各种参数与国际化域名和国际化电子邮件地址。请在 此处此处 找到这些文件的链接。

具体说PHP:

PHP中有一个好的库,即EmailValidator。它是一个电子邮件地址验证器,包括许多验证方法,如DNS验证。特别推荐的验证器称为RFCValidator,可以根据多个RFC验证电子邮件地址。在支持IDN和国际化电子邮件地址方面,它具有良好的兼容性。


0
^[_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%的电子邮件地址,包括一些较新的顶级域名扩展,例如info、museum、name等。它还允许直接绑定到IP地址的电子邮件。


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