如何在JavaScript中验证电子邮件地址?

5476

在将用户输入发送到服务器或尝试向其发送电子邮件之前,为了防止最基本的打字错误,我想在JavaScript中检查用户输入是否为电子邮件地址。 我该如何实现此目标?


23
@Alex 我添加这个评论的原因是,被接受的答案中建议的正则表达式会禁止现有的有效电子邮件地址,这对客户来说是一个很糟糕的开端。而真正大的问题是,即使地址被接受了,也不能确定它是否有效。可靠地验证提供的电子邮件地址是否有效的唯一方法是发送带有验证链接的邮件。因此,如果您的用例不要求验证电子邮件,请只进行最小限度的@测试;否则,请使用验证邮件。正则表达式只会提供糟糕的用户体验。 - David Mårtensson
7
@mikael1000,好的,但是当你根本不知道是否存在有效的电子邮件时,正则表达式验证有什么用处呢?如果您不想使用验证链接干扰客户,则只需进行最简单的验证<something> at <something>,然后就可以了。这将确保客户至少添加了可能是电子邮件的内容,除此之外的任何操作都是代码浪费,直到您实际进行验证为止。您还可以通过DNS查找来检查域名是否存在。 - David Mårtensson
2
非常相似:*如何使用正则表达式验证电子邮件地址?* - Peter Mortensen
我建议阅读这篇关于电子邮件语法如何工作的文章:https://debounce.io/blog/articles/email-syntax-error-explained/ - Iman
3
我必须承认,我不理解为什么要进行这么多验证,因为即使用户没有使用有效字符,也无法预测其是否进行了基本类型的输入。 只需在开头检查@和至少一个点即可。 - Watts Epherson
显示剩余5条评论
79个回答

10

在我的情况下,我想避免使用~#,这就是为什么我使用了另一种解决方案的原因:

function validEmail(email){
  const regex = /^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/;
  return regex.test(email);
}

function validEmail(email){
  const regex = /^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/;
  return regex.test(email);
}

const emails = [
'pio_pio@factory.com',
'~pio_pio@factory.com',
'pio_~pio@factory.com',
'pio_#pio@factory.com',
'pio_pio@#factory.com',
'pio_pio@factory.c#om',
'pio_pio@factory.c*om',
'pio^_pio@factory.com'
]

for(const email of emails){
  document.write(email+' : '+validEmail(email)+'</br>');
}


这个答案 - 以及这个帖子中的其他一些答案 - 没有转义连字符。据我所见(2021年9月),这在浏览器中没有问题 - 至少在Webkit变体中。然而,这可能会改变。在编写时,PHP7.3无法编译正则表达式而不转义连字符。通过转义连字符\-而不仅仅是-来为您的浏览器端代码未来做好准备。 - DroidOS

10

我正在寻找一个JS中的正则表达式,可以通过所有电子邮件地址测试用例:

  • email@example.com 有效的电子邮件

  • firstname.lastname@example.com 电子邮件地址字段中包含点号

  • email@subdomain.example.com 电子邮件中包含带有子域的点

  • firstname+lastname@example.com 加号被视为有效字符

  • email@192.0.2.123 域是有效的IP地址

  • email@[192.0.2.123] 方括号中的IP地址被视为有效

  • "email"@example.com 引号中的电子邮件被视为有效

  • 1234567890@example.com 地址中的数字是有效的

  • email@domain-one.example 域名中的破折号是有效的

  • _______@example.com 地址字段中的下划线是有效的

  • email@example.name .name 是有效的顶级域名

  • email@example.co.jp 顶级域名中的点也被视为有效(此处使用co.jp作为示例)

  • firstname-lastname@example.com 地址字段中的破折号是有效的

这是正则表达式:

http://regexr.com/3f07j

或者使用以下正则表达式:

Regex = /(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@[*[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+]*/

9

这里的大多数答案对于代码检查工具不友好,一团糟!其中一些也已经过时了!

花费了很多时间后,我决定使用名为email-validator的外部库,在项目中轻松地通过npm安装并导入/引用它:

https://www.npmjs.com/package/email-validator

//NodeJs
const validator = require("email-validator");
validator.validate("test@email.com"); // true

//TypeScript/JavaScript
import * as EmailValidator from 'email-validator';
EmailValidator.validate("test@email.com"); // true

这不是问题的答案,但它帮了我并节省了我的时间。这个电子邮件验证程序包似乎每周帮助约50万其他人(下载)。因此值得一提并值得一些赞。 - Stefan

8

我更喜欢保持简洁并让我的用户感到满意。我还更喜欢易于理解的代码。而正则表达式则不是这样。

function isValidEmail(value) {
    const atLocation = value.lastIndexOf("@");
    const dotLocation = value.lastIndexOf("."); 
    return (
        atLocation > 0 &&
        dotLocation > atLocation + 1 &&
        dotLocation < value.length - 1
    );
};
  • 获取最后一个 @ 符号和最后一个 . 符号的位置
  • 确保 @ 不是第一个字符(前面有内容)
  • 确保 . 在 @ 后面,它们之间至少有一个字符
  • 确保 . 后面至少有一个字符

这样是否会允许无效的电子邮件地址通过?当然会,但我认为为了良好的用户体验,你只需要用它来启用/禁用按钮、显示错误消息等。只有在尝试向该地址发送电子邮件时,才能确定电子邮件地址是否有效。


这将无法处理以包含 @ 的注释结尾的电子邮件,例如“elldffs@mydomain.kjfdij(这是@评论)”,这是有效的电子邮件。 - David Mårtensson

7
微软在 ASP.NET MVC 中提供的正则表达式为:
/^[\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$/

我在这里发布它,以防它有缺陷 - 尽管它一直完美地满足了我的需求。


1
电子邮件名称部分不允许出现“+”号。 - Paul Gordon

6
这是一个JavaScript翻译版本,它是数千个网站使用的官方Rails指南建议的验证方法:
/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i

这个测试相对简单,但可以检测出大多数常见的错误。

在成千上万封电子邮件的数据集上测试,它的假阴性/假阳性率为零。

使用示例:

const emailRegex = /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i;

emailRegex.test('email@example.com');    // true

// Multi-word domains
emailRegex.test('email@example.co.uk');  // true
emailRegex.test('email@mail.gmail.com'); // true

// Valid special characters
emailRegex.test('unusual+but+valid+email1900=/!#$%&\'*+-/=?^_`.{|}~@example.com') // true

// Trailing dots
emailRegex.test('email@example.co.uk.'); // false

// No domain
emailRegex.test('email@example');        // false

// Leading space
emailRegex.test(' email@example.com');   // false

// Trailing space
emailRegex.test('email@example.com ');   // false

// Incorrect domains
emailRegex.test('email@example,com ');   // false

// Other invalid emails
emailRegex.test('invalid.email.com')        // false
emailRegex.test('invalid@email@domain.com') // false
emailRegex.test('email@example..com')       // false

6
Sectrean的解决方案很好,但它无法通过我的linter。因此我添加了一些转义字符:
function validateEmail(email){ 
     var re = /^(([^<>()[]\\.,;:\s@\"]+(\.[^<>()[]\\.,;:\s@\"]+)*)|(\".+\"))@(([[0-9]{1,3}\‌​.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 
     return re.test(email); 
}

validateEmail("e_mail@sth.com") 和 validateEmail("e.mail@sth.com") 都返回 false 值。 - Ikrom

6
最佳实践是使用HTML5内置的电子邮件标签。
<input type="email" name="email">

下面是识别字符串中常见的电子邮件语法,包括识别 @ 和 . 符号的方法。
^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-.]+$

请注意,这仍然会生成无效的电子邮件,但仍将与正则表达式匹配,几乎不可能全部捕获,但这将稍微改善情况。

这很好,但问题在于它必须在表单标签内,并由提交输入提交,而不是每个人都有这种奢侈条件。此外,您无法真正样式化错误消息。 - @Jason Nov 12 '2011 at 0:08 - aNewb

5
这是我用于前端电子邮件验证的函数。(正则表达式来自 parsley.js)
<!DOCTYPE html>
<html>
<head>
    <title>Our Company</title>
    <style>
        .form-style {
            color: #ccc;
        }
    </style>
</head>
<body>
    <h1>Email Validation Form Example</h1>
    <input type="text" name="email" id="emailInput" class="form-style">
    <script>
        function validateEmail(emailAddress) {
            var regularExpression = /^((([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]))){2,6}$/i;
             return regularExpression.test(emailAddress);
        }

        function showEmailValidationState(event) {
            if (validateEmail(event.target.value)) {
                document.getElementById("emailInput").style.color = 'black';
            }
        }
    document.getElementById("emailInput").addEventListener("keyup", showEmailValidationState);
    </script>
</body>
</html>

5
这个问题的答案是(如果你退后一步思考)你不能真正防止用户输入错误的电子邮件。每个人都提供了匹配所有可能字母的答案,但没有人真正考虑过可以使用的全部字符。
我参考了这篇文章和解释可接受字符数量的答案: Remove invalid characters from e-mail 您无法预测用户输入的字母是否与他们预期相同——这是最常见的错误,漏掉一个字母或输入错误的字母。
最终,无论你在Javascript中做什么,你总是需要你的后端脚本来检查电子邮件是否发送成功,并且它可能已经有一个验证过程。
因此,如果您想确保它是某种电子邮件地址而不是他们的用户名,则只需要检查其中是否有@符号和至少1个点,并将其余部分留给后端代码。
我提供了一个非常基本的函数,演示了实时输入的延迟检查和即时检查。 JavaScript作为首个检查点有效地验证基础内容,以避免发布无效内容并打扰用户。
然而,它始终假定后端的大量检查是必需的。

// Very simple, non-library dependent client-side  e-mail validator
var emailv = {

  // Timeout handler for checkDelay()
  to: null, 
  
  // The core function that takes a string and validates it
  check : function(em){
    
    // Check 1 - The split ensures there's only one @
    var c1 = em.split('@').length == 2;
    
    // Check 2 - Must be at least 1 dot too
    var c2 = em.indexOf('.') > 0;
    
    // Check 3 - ensures there's always something after a @ or dot
    var c3 = !(em.slice(-1)=="@"||em.slice(-1)==".");
    return (c1&&c2&&c3); // If all TRUE, great.
  },
  
  // Shortcut to quickly check any text input by dom id
  checkById : function(inputId){
    d = document.getElementById(inputId);
    return d?emailv.check(d.value):false;
  },
  
  // Check delay for checking on real-time inputs
  checkDelay: function(em){
      clearTimeout(emailv.to);
      emailv.to = setTimeout("emailv.checkDelayP2('"+em+"')",1000);
  },
  
  // Part two  of Check delay
  checkDelayP2: function(em){ 
      if(emailv.check(em)){ // Javascript filter says it seems okay

        // For sakes of this demo, pretend we are now making a background
        // check to see if e-mail is taken. We tell the user to wait..
        emailv.status("Wait..");

        // Pretend the background check took 2 seconds
        // and said e-mail was available
        setTimeout("emailv.status('OK')",2000);
      } else {
        // Javascript say it's bad, mmmkay?
         emailv.status("BAD E-mail");      
      }
  },
  
  status : function(s){
    document.getElementById('emailstatus').innerHTML=s;
  }
}
<h2>1 of 2 - Delayed check</h2>
<ul>
<li><strong>Waits until the user has stopped typing</strong></li>
<li>Useful for when you want to then send e-mail to background database to check if it exists.</li>
<li>Allows them 1 idle second before checking the e-mail address.</li>
</ul>
<input type="text" size="50" id="youremail" name="youremail" onkeyup="emailv.checkDelay(this.value)" onpaste="emailv.checkDelay(this.value)" />
<span id='emailstatus'></span>


<h2>2 of 2 - Instant Check</h2>
<input type="text" size="50" id="youremail2" name="youremail2" />
<a href="Javascript:void(0)" onclick="alert(emailv.checkById('youremail2')?'Seems okay to me':'This e-mail is dodgy')">Check e-mail</a>

避免限制过多变得复杂,不如避免让用户输入有效的电子邮件。

这只是我的观点!


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