如何检查有效的电子邮件地址?

277 投票
18 回答
441751 浏览
提问于 2025-04-17 05:42

有没有什么好的方法可以用正则表达式来检查表单输入,确保它是一个正确格式的电子邮件地址?我从昨晚开始就一直在找这个,发现那些回答这个问题的人似乎也对子域名的电子邮件地址有些困惑。

18 个回答

94

我在这里没有看到已经有人回答这个问题,虽然有很多关于自定义正则表达式的答案,但...

有一个叫做 py3-validate-email 的Python库,它提供了三种级别的邮箱验证方法,其中包括询问一个有效的SMTP服务器来检查邮箱地址是否有效(而不需要发送邮件)。

安装方法:

python -m pip install py3-validate-email

基本用法:

from validate_email import validate_email
is_valid = validate_email(email_address='example@example.com', \
    check_regex=True, check_mx=True, \
    from_address='my@from.addr.ess', helo_host='my.host.name', \ 
    smtp_timeout=10, dns_timeout=10, use_blacklist=True)

对于那些对细节感兴趣的人,validate_email.py (源代码) 旨在忠实于 RFC 2822

我们实际上是在将输入的字符串与一个巨大的正则表达式进行比较。但构建这个正则表达式,并确保它的正确性,通过将其从RFC定义的“标记”中组装起来会简单得多。每个标记都会在相应的单元测试文件中进行测试。


可能 需要 pyDNS 模块来检查SMTP服务器

pip install pyDNS

或者从Ubuntu安装:

apt-get install python3-dns
178

Python的标准库里有一个用来解析电子邮件的功能:email.utils.parseaddr()

这个功能会返回一个包含真实姓名和实际地址的二元组,也就是两个部分:

>>> from email.utils import parseaddr
>>> parseaddr('foo@example.com')
('', 'foo@example.com')

>>> parseaddr('Full Name <full@example.com>')
('Full Name', 'full@example.com')

>>> parseaddr('"Full Name with quotes and <weird@chars.com>" <weird@example.com>')
('Full Name with quotes and <weird@chars.com>', 'weird@example.com')

如果解析失败,它会返回一个包含空字符串的二元组:

>>> parseaddr('[invalid!email]')
('', '')

这个解析器有个问题,就是它接受任何被认为是有效的电子邮件地址,包括很多明显在互联网上无法使用的地址,这些地址符合RFC-822标准:

>>> parseaddr('invalid@example,com') # notice the comma
('', 'invalid@example')

>>> parseaddr('invalid-email')
('', 'invalid-email')

所以,正如@TokenMacGuy所说,检查电子邮件地址的唯一可靠方法就是发一封邮件到预期的地址,然后等用户对邮件里的信息做出反应。

不过,至少你可以检查一下第二个部分里是否有一个@符号,正如@bvukelic所建议的那样:

>>> '@' in parseaddr("invalid-email")[1]
False

如果你想更进一步,可以安装dnspython这个项目,来解析电子邮件域名(也就是@后面的部分)的邮件服务器,只有在有实际的MX服务器时才尝试发送邮件:

>>> from dns.resolver import query
>>> domain = 'foo@bar@google.com'.rsplit('@', 1)[-1]
>>> bool(query(domain, 'MX'))
True
>>> query('example.com', 'MX')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  [...]
dns.resolver.NoAnswer
>>> query('not-a-domain', 'MX')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  [...]
dns.resolver.NXDOMAIN

你可以通过捕获dns.exception.DNSException来处理NoAnswerNXDOMAIN这两种情况。

而且,foo@bar@google.com在语法上是有效的地址。只有最后一个@应该被用来判断域名部分的开始。

354

其实没有必要。即使你能确认这个邮箱地址在格式上是正确的,你还是需要检查一下它是不是输入错误了,以及它确实是发给你想发的人。唯一能做到这一点的方法就是给他们发一封邮件,让他们点击一个链接来确认。

所以,最基本的检查(比如说他们没有不小心输入自己的街道地址)通常就够了。比如:邮箱里应该有一个@符号,并且在@后面至少要有一个.

[^@]+@[^@]+\.[^@]+

你可能还想禁止空格——虽然可能有有效的邮箱地址里包含空格,但我从来没见过,所以这很可能是用户输入错误的几率更大。

如果你想要更全面的检查,可以看看这个问题


更新:这是你可以使用的正则表达式:

import re

if not re.match(r"... regex here ...", email):
  # whatever

Python 版本≥3.4 有re.fullmatch,比re.match更好用。

注意字符串前面的r;这样你就不需要把某些字符转义两次了。

如果你有很多正则表达式需要检查,先编译正则表达式可能会更快:

import re

EMAIL_REGEX = re.compile(r"... regex here ...")

if not EMAIL_REGEX.match(email):
  # whatever

另一个选择是使用validate_email这个包,它实际上会联系SMTP服务器来验证这个地址是否存在。不过,这仍然不能保证它属于正确的人。

撰写回答