我有这个功能来验证一个电子邮件地址:

function validateEMAIL($EMAIL) {
    $v = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";

    return (bool)preg_match($v, $EMAIL);
}

这样可以检查电子邮件地址是否有效吗?


当前回答

我准备了一个检查电子邮件有效性的函数:

function isValidEmail($email)
{
    $re = '/([\w\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)/m';
    preg_match_all($re, $email, $matches, PREG_SET_ORDER, 0);
    if(count($matches) > 0) return $matches[0][0] === $email;
    return false;
}

FILTER_VALIDATE_EMAIL的问题是,它甚至认为无效的电子邮件是有效的。

以下是例子:

if(isValidEmail("foo@gmail.com")) echo "valid";
if(!isValidEmail("fo^o@gmail.com")) echo "invalid";

其他回答

检查电子邮件地址是否格式良好的最简单和最安全的方法是使用filter_var()函数:

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    // invalid emailaddress
}

此外,您可以检查域是否定义了MX记录:

if (!checkdnsrr($domain, 'MX')) {
    // domain is not valid
}

但这仍然不能保证邮件存在。唯一的办法就是发送确认邮件。


现在你已经有了简单的答案,如果你想学习,可以继续阅读关于电子邮件地址验证的内容,或者只是使用快速答案并继续前进。别见怪不怪。

尝试使用正则表达式验证电子邮件地址是一项“不可能”的任务。我想说的是,你所做的正则表达式是无用的。关于电子邮件地址有三个rfc,编写一个正则表达式来捕获错误的电子邮件地址,同时避免误报,这是没有人能做到的。查看PHP的filter_var()函数所使用的正则表达式的测试列表(包括失败和成功)。

即使是内置的PHP函数,电子邮件客户端或服务器也没有做到这一点。在大多数情况下,filter_var仍然是最好的选择。

如果你想知道PHP(目前)使用哪种正则表达式模式来验证电子邮件地址,请参阅PHP源代码。

如果你想了解更多关于电子邮件地址的信息,我建议你开始阅读说明书,但我必须警告你,无论如何,这都不是一个简单的阅读:

rfc5322 rfc5321 rfc3696 Rfc6531(允许unicode字符,尽管许多客户端/服务器不接受它)

使用以下代码:

// Variable to check
$email = "john.doe@example.com";

// Remove all illegal characters from email
$email = filter_var($email, FILTER_SANITIZE_EMAIL);


// Validate e-mail
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
  echo("Email is a valid email address");
}

在FILTER_VALIDATE_EMAIL中有一个更好的正则表达式,但任何正则表达式都可能给出糟糕的结果。

例如. .

// "not an email" is invalid so its false.
php > var_export(filter_var("not an email", FILTER_VALIDATE_EMAIL));
false
// "foo@a.com" looks like an email, so it passes even though its not real.
php > var_export(filter_var("foo@a.com", FILTER_VALIDATE_EMAIL));
'foo@a.com'
// "foo@gmail.com" passes, gmail is a valid email server,
//  but gmail require more than 3 letters for the address.
var_export(filter_var("foo@gmail.com", FILTER_VALIDATE_EMAIL));
'foo@gmail.com'

你可能会考虑使用像Real Email这样的API,它可以进行深入的邮箱检查,以检查电子邮件是否真实。

有点像…

$email = "foo@bar.com";
$api_key = ???;

$request_context = stream_context_create(array(
    'http' => array(
        'header'  => "Authorization: Bearer " . $api_key
    )
));

$result_json = file_get_contents("https://isitarealemail.com/api/email/validate?email=" . $email, false, $request_context);

if (json_decode($result_json, true)['status'] == "valid") {
    echo("email is valid");
} else if (json_decode($result_json, true)['status'] == "invalid") {
    echo("email is invalid");
} else {
  echo("email was unknown");
}

根据我的经验,regex解决方案有太多的假阳性,而filter_var()解决方案有假阴性(特别是对于所有新的tld)。

相反,最好是确保地址具有电子邮件地址的所有必需部分(用户、“@”符号和域),然后验证域本身是否存在。

无法确定(服务器端)外部域是否存在电子邮件用户。

这是我在Utility类中创建的一个方法:

public static function validateEmail(string $email): bool {

    // SET INITIAL RETURN VARIABLE
    // ENSURE -> EMAIL ISN'T EMPTY | AN @ SYMBOL IS PRESENT 

        $emailIsValid = FALSE;

        if (
            !empty($email) &&
            strpos($email, '@') !== FALSE
        ) {

            // GET EMAIL PARTS

                $email  = explode('@', $email);
                $user   = $email[0];
                $domain = $email[1];

            // VALIDATE EMAIL ADDRESS

                if (
                    count($email) === 2 &&
                    !empty($user) &&
                    !empty($domain) &&
                    checkdnsrr($domain)
                ) {
                    $emailIsValid = TRUE;
                }
        }

    // RETURN RESULT

        return $emailIsValid;
}

有三个rfc奠定了“Internet消息格式”的基础。

RFC 822 RFC 2822(取代RFC 822) RFC 5322(取代RFC 2822)

然而,RFC 5322以最专业的方式定义了电子邮件id及其命名结构。这更适合于为一个互联网标准奠定基础,这个标准足够自由,可以允许所有的用例,也足够保守,可以用某种形式主义来约束它。

然而,来自软件开发人员社区的电子邮件验证需求,有以下需求——

避免不必要的垃圾邮件发送者 确保用户不会因疏忽而出错 以确保电子邮件ID属于实际输入它的人

They are not exactly interested in implementing a technically all-encompassing definition that allows all the forms (IP addresses, including port IDs and all) of e-mail id. The solution suitable for their use-case is expected to solely ensure that all the legitimate e-mail holders should be able to get through. The definition of "legitimate" differs vastly from technical stand-point (RFC 5322 way) to usability stand-point(this solution). The usability aspect of the validation aims to ensure that all the e-mail IDs validated by the validation mechanism belong to actual people, using them for their communication purposes. This, thus introduces another angle to the validation process, ensuring an actually "in-use" e-mail ID, a requirement for which RFC-5322 definition is clearly not sufficient.

因此,在实际的基础上,实际的要求归结为这一点

以确保一些非常基本的验证检查 确保输入的电子邮件正在使用

第二个需求通常包括向输入的电子邮件ID发送标准响应,并根据响应机制中描述的操作对用户进行身份验证。这是用于确保验证“使用中”电子邮件ID的第二个需求的最广泛使用的机制。这确实涉及到从后端服务器实现的往返,并且不是一个直接的单屏幕实现,但是,我们不能放弃这一点。

The first requirement, stems from the need that the developers do not want totally "non e-mail like" strings to pass as an e-mail. This typically involves blanks, strings without "@" sign or without a domain name. Given the punycode representations of the domain names, if one needs to enable domain validation, they need to engage in full-fledged implementation that ensures a valid domain name. Thus, given the basic nature of requirement in this regard, validating for "<something>@<something>.<something>" is the only apt way of satisfying the requirement.

一个典型的正则表达式可以满足这个要求: ^ ^ @ \ [s] + @ ^ @ \ [s] + [^ @ \ s]。+ $ 上面的正则表达式遵循大多数编程语言都广泛遵循的标准Perl正则表达式标准。验证语句是: <除空格和“@”符号>之外的任何东西@<除空格和“@”符号>之外的任何东西。<除空格、@符号和点>之外的任何东西

对于那些想要更深入地了解更相关的实现的人,他们可以遵循以下验证方法。 <电子邮件本地部分>@<域名>

对于<电子邮件本地部分> -遵循“通用验收指导小组”- UASG-026的指导方针 对于<域名>,您可以使用标准库遵循任何域验证方法,这取决于您的编程语言。关于该主题的最新研究,请参考文档UASG-018A。

那些有兴趣了解在实施国际化电子邮件解决方案时可能遇到的整体流程、挑战和问题的人,也可以通过以下rfc:

RFC 6530(国际化电子邮件概述和框架) RFC 6531(国际化电子邮件的SMTP扩展名) RFC 6532(国际化邮件头) RFC 6533(国际化交付状态和处置通知) RFC 6855 (IMAP支持UTF-8) RFC 6856(邮局协议版本3 (POP3)支持UTF-8) RFC 6857(国际化电子邮件消息的发送后消息降级) RFC 6858(简化POP和IMAP降级国际化电子邮件)。