电子邮件地址验证方法(订阅按钮)

6
我正在使用php编写网站,目前在联系我们页面上,想知道验证电子邮件地址的最佳方法是什么?
  1. 通过向其电子邮件发送验证链接?
  2. 正则表达式
  3. 其他任何方法?
此外,您能告诉我为什么以及如何实现吗?我不希望有人为我编写代码,因为这对我来说没有乐趣,并且我不会学到东西,但只需要指导一下实现以上方法所使用的技术。
另外,我将使用这些方法在我的网页上实现一个订阅按钮。这是最好的方法吗?还有其他方法应该考虑吗?

1
可能是重复问题:https://dev59.com/uHVC5IYBdhLWcg3wtzut - Anax
2
正则表达式无法验证电子邮件,它只能验证用户输入是否类似于电子邮件。(例如adasdsa@dadsd.com将被验证) 如果您真的需要验证,您必须发送验证电子邮件。 - ahmetunal
10个回答

16

我通常会按照以下步骤进行:

  1. 正则表达式
  2. 向电子邮件发送激活码

如果第一步失败,则不会执行第二步。 如果发送电子邮件失败是因为该电子邮件不存在,我会删除帐户或执行其他操作。

--编辑

3- 如果由于某些原因激活电子邮件未能发送,电子邮件未被删除,它会保持未批准状态 7 天(或由您配置),每隔 2-3 小时尝试重新发送电子邮件,在这些天之后,如果没有成功,则删除电子邮件

4- 如果电子邮件成功发送但未激活,则保持未批准状态,但可通过生成新的激活码随时重新激活。


我还想补充一点,为了用户方便起见,可以给未经验证的用户分配某种“预先批准”的状态,这样当邮件传递缓慢时,用户仍然可以使用您的服务。此外,在正则表达式中不要过于严格,只需确保它“有点像电子邮件地址”,您不希望出现太多错误的结果。 - Dennis Haarbrink
@ Dennis:我认为,仅仅输入一个看似正确但有可能是错误的电子邮件地址,并不足以给予用户更多访问权限。 - Steven Sudit
请不要使用正则表达式验证电子邮件地址。因为无法编写一个完全匹配RFC2822规范的正则表达式,你最终会得到假阳性和假阴性。假阴性是一个大问题,因为它们会阻止有效的电子邮件地址通过。Jeffrey Friedl在《精通正则表达式》中开发了一个电子邮件匹配正则表达式。它大约有7000个字符长,并且可以匹配98%的有效地址格式。最好使用使用此正则表达式的库。 - bluesmoon

11

我认为最好的方法是将第3种和第1种方法结合起来。

在最初阶段,您应该对电子邮件进行语法验证(以捕获拼写错误):

filter_var($email, FILTER_VALIDATE_EMAIL)

其次,您可以发送一封电子邮件,并在其中包含确认链接(这样可以同时捕获错误和故意提供错误信息)。


5
人们需要了解filter_var(),它非常棒。 - BoltClock

4

最好的方法是发送一封带有验证链接的电子邮件。如果您不想要激活电子邮件,至少验证电子邮件地址。最好的电子邮件验证函数是 Dominic Sayers 的RFC兼容电子邮件地址验证器

只需在项目中包含php文件,并像这样使用:

if (is_email($email, $checkDNS, $diagnose)) //$checkDNS and $diagnose are false by default
    echo 'Email valid';
else
    echo 'Email invalid';
  • 如果 $checkDNS 设置为 true,则会验证域名是否存在。即使电子邮件地址有效,如果域名不存在,该函数也会返回 false。
  • 如果 $diagnose 设置为 true,则函数返回一个代码而不是布尔值,告诉您为什么电子邮件无效(如果有效则返回 0)。

3

这取决于用户是否真的想要收到回复。

如果用户提出问题,他会想要回答并可能提供有效的电子邮件地址。在这种情况下,我会使用非常宽松的正则表达式检查来捕获拼写错误或缺少地址。(类似于.+@.+

如果用户不想被联系,但您想知道他们的地址,您需要使用验证链接。没有其他方法可以确保电子邮件地址是有效的并属于用户。


3
唯一确认电子邮件地址是否有效的方法是向该地址发送电子邮件。如果必须这样做,请使用这些之一。 技术上讲,本地域名后面甚至不需要加任何句号。只需在@后面跟随一个域名即可。

2
等到人们开始将IPv6冒号分隔的值作为他们的域名时,就会出现这种情况。 :-) - Steven Sudit

2
正文:
正则表达式并不适合确定电子邮件地址语法的有效性,而filter_var函数的FILTER_VALIDATE_EMAIL选项也相当不可靠。我使用EmailAddressValidator Class来测试电子邮件地址语法。
我列举了一些filter_var返回的错误结果示例(PHP Version 5.3.2-1ubuntu4.2)。可能还有更多。有些确实有点极端,但仍值得注意: RFC 1035 2.3.1. 首选名称语法
https://www.rfc-editor.org/rfc/rfc1035
总结为:一个域名由标签组成,标签之间用点分隔符分隔(尽管对于本地域名来说并非如此)。
echo filter_var('name@example', FILTER_VALIDATE_EMAIL);
// name@example

RFC 1035 2.3.1. 首选名称语法
标签必须遵循 ARPANET 主机名的规则。它们必须以字母开头,以字母或数字结尾,并且内部字符只能是字母、数字和连字符。
echo filter_var('name@1example.com', FILTER_VALIDATE_EMAIL);
// name@1example

RFC 2822 3.2.5. 引用字符串 https://www.rfc-editor.org/rfc/rfc2822#section-3.2.5 这是有效的(尽管被许多邮件服务器拒绝):
echo filter_var('name"quoted"string@example', FILTER_VALIDATE_EMAIL);
// FALSE

RFC 5321 4.5.3.1.1. 本地部分
https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.1.1
用户名称或其他本地部分的最大总长度为64个八位字节。
测试70个字符:
echo filter_var('AbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghij@example.com', FILTER_VALIDATE_EMAIL);
// AbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghij@example.com

RFC 5321 4.5.3.1.2. 域名
https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.1.2
域名或数字的最大总长度为255个八位字节。
测试260个字符的情况:
echo filter_var('name@AbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghij.com', FILTER_VALIDATE_EMAIL);
// name@AbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghijAbcdefghij.com

请查看使用正确的方式在PHP中验证电子邮件地址获取更多信息。

1
Doug Lovell在Linux Journal上的文章在多个方面事实上是错误的。他重复了RFC 3696中原始错误,这些错误现在已经在勘误表中得到了纠正。不幸的是,Linux Journal并没有认为有必要更正这篇误导性的文章,它仍然被引用为权威资料。 - Dominic Sayers

2
在发送验证电子邮件之前,您还可以使用checkdnsrr()来验证域是否存在并且是否设置了MX记录。这将检测使用虚假域名(如user@idontexist.com)的电子邮件。请注意保留HTML标签。
function validateEmail($email, $field, $msg = '')
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL))
    {
        return false;
    }
    list($user, $domain) = explode('@', $email);
    if (function_exists('checkdnsrr') && !checkdnsrr($domain, 'MX'))
    {
        return false;
    }
    return true;
}

在 PHP 5.3 之前的 Windows 版本中,checkdnsrr() 函数不可用,因此我们需要使用 function_exists() 来验证其是否可用。


1
你认为为什么MX记录是电子邮件传递所必需的?"如果没有MX记录存在,服务器会回退到A记录,也就是说,它会请求同一域的A记录。" - sanmai
@sanmai 虽然在理论上可能是正确的,但在实践中你很少看到这种情况发生。此外,在验证电子邮件地址方面,除了向该地址发送电子邮件并等待响应之外,没有自动化的过程能够完美地执行。包括这种方法也是如此。但如果提供错误的电子邮件地址是一个问题,那么这将有助于减轻这种情况。 - John Conde
@john-conde 我至少见过这种情况发生了几次。想象一下,你向经理描述为什么你的重要客户无法使用他的工作电子邮件地址注册。 - sanmai
我也看到了sanmai提到的同样情况。虽然不常见,但确实存在。无论如何,最终检查MX记录并不能为您带来太多好处,所以我不会费心去检查。 - Steven Sudit
嗯。也许这个最好作为决定一个电子邮件地址是否合法的多个因素之一来使用?只能与其他测试配合使用。 - John Conde

1

这取决于您的目标。如果您必须拥有一个有效和活跃的电子邮件,那么您必须发送一封需要验证收据的电子邮件。在这种情况下,除了方便用户之外,没有必要进行正则表达式验证。

但是,如果您的愿望是帮助用户避免输错,同时最大程度地减少用户的烦恼,请使用正则表达式进行验证。


0

这里有一些好的答案,我同意所选择的答案,除了正则表达式部分。正如其他人指出的那样,很难找到一个完全实现RFC 5321所有怪癖的正则表达式。

欢迎使用我的免费PHP函数is_email()来验证地址。它可以在这里找到。

它将确保地址完全符合RFC 5321规范。它还可以可选地检查域名是否实际存在。

您不应该依赖验证器告诉您用户的电子邮件地址实际上是否存在:一些ISP向他们的用户提供不符合规范的地址,特别是在不使用拉丁字母的国家/地区。更多关于电子邮件验证的信息,请参见我的文章http://isemail.info/about


-1
 function checkEmail($email) {
  if(preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])
  ↪*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/",
               $email)){
    list($username,$domain)=split('@',$email);
    if(!checkdnsrr($domain,'MX')) {
      return false;
    }
    return true;
  }
  return false;

1
你的正则表达式拒绝了许多有效的电子邮件地址。例如 *@example.com,"Hello world"@example.com,someone@[127.0.0.1],someone@[2001:1234:1234::1.2.3.4]。 - jcoder
虽然我可以放过你的ipv6不匹配,但是正则表达式的其余部分太差了,无法考虑。 - symcbean

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