Is there a good way to check a form input using regex to make sure it is a proper style email address? Been searching since last night and everybody that has answered peoples questions regarding this topic also seems to have problems with it if it is a subdomained email address.
18 Answers
There is no point. Even if you can verify that the email address is syntactically valid, you'll still need to check that it was not mistyped, and that it actually goes to the person you think it does. The only way to do that is to send them an email and have them click a link to verify.
Therefore, a most basic check (e.g. that they didn't accidentally entered their street address) is usually enough. Something like: it has exactly one @
sign, and at least one .
in the part after the @
:
[^@]+@[^@]+\.[^@]+
You'd probably also want to disallow whitespace -- there are probably valid email addresses with whitespace in them, but I've never seen one, so the odds of this being a user error are on your side.
If you want the full check, have a look at this question.
Update: Here's how you could use any such regex:
import re
if not re.match(r"... regex here ...", email):
# whatever
Python ≥3.4 has re.fullmatch
which is preferable to re.match
.
Note the r
in front of the string; this way, you won't need to escape things twice.
If you have a large number of regexes to check, it might be faster to compile the regex first:
import re
EMAIL_REGEX = re.compile(r"... regex here ...")
if not EMAIL_REGEX.match(email):
# whatever
Another option is to use the validate_email
package, which actually contacts the SMTP server to verify that the address exists. This still doesn't guarantee that it belongs to the right person, though.
-
1So than basically my best bet would be `if not re.match("[^@]+@[^@]+\.[^@]+", email):` ? – Bobby Nov 05 '11 at 19:15
-
27I ended up doing `if not re.match(r"^[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*$", email):` as this seem the most plausible scenario followed by sending an verification email to the given address. – Bobby Nov 05 '11 at 19:44
-
+1 for the quickie re.match(r"xx") tutorial. Inlining what is necessary is the mark of a good answer. – JohnnyLambada Nov 17 '12 at 15:58
-
28@Bobby: *please* loosen that up a lot. I've had to deal with email addresses that that would filter out (e.g. with `/`, seen in a University's addresses). Another whole class that you're entirely blocking are internationalised domain names. Really, there's no good reason to block valid email addresses. I'll begrudgingly forgive people that don't allow email addresses like `100%." foo b@r"(this is a cool email address!)@(just a tld)com(ok)`, but I think the check for an `@` symbol is really all you should have (a top level domain is valid as the domain part, but it's improbable). – Chris Morgan Mar 06 '13 at 06:30
-
I wanted something a little tighter than this answer. In particular, no whitespace, can't end with a period, and matches through the end of the string. This should catch 99% of typos. Here it is: `EMAIL_REGEX = re.compile(r"[^@\s]+@[^@\s]+\.[^@\s.]+$")` – new name Aug 18 '15 at 01:30
-
2Making it even a little tighter. Seems safe to limit TLD to alphanumeric right now (still haven't seen a TLD that has non-ASCII chars). Using this now: `re.compile(r"[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$")` – new name Aug 29 '15 at 15:39
-
Except that `"@"@localhost` and `\@@localhost` are valid. – Julien Palard Oct 03 '16 at 11:01
-
I like this answer the most however if you do want to add some more robustness to the local part of the email (before the @) while still keeping the general "there is no point attitude" you can do something like: ``r'[\w!#$%&\'*+-/=?^_`{|}~.]+@[\w\.-]+'`` – sponrad Apr 11 '18 at 16:31
-
*hijacking the accepted answer*: take a look at this non-regex answer with python libs, including checking if the domain has an smtp server and even polling the smtp server to see if the email exists: https://stackoverflow.com/a/28982264/2327328 – philshem Sep 14 '18 at 08:59
-
if anyone is unsure, the [^@] means match anything except @. I was unsure myself and found the answer @w3schools don't laugh ! – joedotnot Apr 11 '19 at 06:56
-
[^<\s@]+@[^\s@]+\.[a-zA-Z]+ using the answer and comments came up with this. If using SMTP stuff you might have brackets around your address and your address might be preceded by a person's name. This should extract the address only, no brackets. – DonkeyKong Jun 04 '19 at 14:42
-
One note for `fullmatch`, in my case for emails like "to1@domain.com" it does match, but doesn't fullmatch. Match is actually `to1@domain.c`, so `om` is omitted. – milosmns Jul 28 '19 at 12:27
-
Sorry but "it has exactly one sign @" is a wrong assumption. – Snowirbis Nov 17 '20 at 13:44
-
3@Snowirbis I don't know about the RFC, but I have never seen a _practical_ example of an email address with more than one `@`. If this does occur, it's more likely to be user error (for example, the user hit Ctrl+V twice by accident) than someone's actual email address. – Thomas Nov 18 '20 at 10:20
-
note that the above regexp is vulnerable to ReDOS attack https://www.geeksforgeeks.org/understanding-redos-attack/ – Moussawi7 Jul 21 '22 at 08:36
-
@Moussawi7 That's interesting. Can you elaborate? What kind of inputs would result in exponential-time behaviour? – Thomas Jul 21 '22 at 10:27
-
@Thomas sorry I deleted my comments, like you mentioned wrong thread – alper Jun 29 '23 at 11:33
The Python standard library comes with an e-mail parsing function: email.utils.parseaddr()
.
It returns a two-tuple containing the real name and the actual address parts of the e-mail:
>>> 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')
And if the parsing is unsuccessful, it returns a two-tuple of empty strings:
>>> parseaddr('[invalid!email]')
('', '')
An issue with this parser is that it's accepting of anything that is considered as a valid e-mail address for RFC-822 and friends, including many things that are clearly not addressable on the wide Internet:
>>> parseaddr('invalid@example,com') # notice the comma
('', 'invalid@example')
>>> parseaddr('invalid-email')
('', 'invalid-email')
So, as @TokenMacGuy put it, the only definitive way of checking an e-mail address is to send an e-mail to the expected address and wait for the user to act on the information inside the message.
However, you might want to check for, at least, the presence of an @-sign on the second tuple element, as @bvukelic suggests:
>>> '@' in parseaddr("invalid-email")[1]
False
If you want to go a step further, you can install the dnspython project and resolve the mail servers for the e-mail domain (the part after the '@'), only trying to send an e-mail if there are actual MX
servers:
>>> 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
You can catch both NoAnswer
and NXDOMAIN
by catching dns.exception.DNSException
.
And Yes, foo@bar@google.com
is a syntactically valid address. Only the last @
should be considered for detecting where the domain part starts.

- 57,944
- 17
- 167
- 143

- 14,191
- 6
- 32
- 38
-
5@PeterLada: You could just check if there's a `@` in the address after using this func, though. – Jun 26 '14 at 19:16
-
-
1
-
3@Yajo, "break this" how?`evil@addr` is just as valid an e-mail address as `nonexistinglogin@valid-domain.com` and is treated as such by `parseaddr()`. In the end, you'll always need to try sending an e-mail to the provided address for validation. – LeoRochael Oct 25 '15 at 18:32
-
5email.utils.parseaddr parses email address but does not validate it `email.utils.parseaddr('user@@host')` yields `('', 'user@')` – skoval00 Feb 15 '17 at 16:04
-
@skoval00, that looks like a bug in parseaddr... it should have been parsed as `('', 'user@@host')` instead I think. – LeoRochael Feb 16 '17 at 14:21
-
@skoval00, exactly, I tried this one: In [8]: parseaddr('VIRUS
') Out[8]: ('VIRUS', 'virus!@variable.') – Han.Oliver Sep 08 '18 at 04:03 -
if I pass in an invalid address: 'doijf oijoij yoyoyo@yoyo.com' it returns a valid tuple of ('', 'doijf oijoij yoyoyo@yoyo.com'). How does a space get through the validation....? – DonkeyKong Jun 04 '19 at 13:14
-
-
I'm not sure why so many upvotes. This is useless since it does pretty much no validations whatsoever, which was the original question. – Bryan Williams May 08 '23 at 14:19
I haven't seen the answer already here among the mess of custom Regex answers, but...
There exists a python library called py3-validate-email validate_email which has 3 levels of email validation, including asking a valid SMTP server if the email address is valid (without sending an email).
To install
python -m pip install py3-validate-email
Basic usage:
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)
For those interested in the dirty details, validate_email.py (source) aims to be faithful to RFC 2822.
All we are really doing is comparing the input string to one gigantic regular expression. But building that regexp, and ensuring its correctness, is made much easier by assembling it from the "tokens" defined by the RFC. Each of these tokens is tested in the accompanying unit test file.
you may need the pyDNS module for checking SMTP servers
pip install pyDNS
or from Ubuntu
apt-get install python3-dns
-
1`sudo apt-get python3-dns` seems to work on Ubuntu in place of `sudo -H pip3 install pyDNS`, just for the record. – Brōtsyorfuzthrāx Sep 01 '18 at 23:13
-
7
-
@Prof.Falken which of the 3 tests are you referring to (valid syntax, valid smtp, valid mailbox)? – philshem Sep 28 '18 at 06:47
-
5@philshem, well, the two deeper tests supposed to go out to the mail servers, both return "None" all the time. Don't know why, I will try to rule out that I have some kind of limitation on the network I am on. The simple test, valid syntax, I can throw just about anything to and it will say it's good syntax. I used the pip module in Python 2. – Prof. Falken Sep 28 '18 at 13:09
-
2
-
2This is a pretty bad validator. It fails for `email@examplecom`. See the big list of known [issues](https://github.com/syrusakbary/validate_email/issues). – Asclepius Mar 14 '19 at 01:21
-
There seems to be a newer version for validate_email : https://pypi.org/project/py3-validate-email/. – Krishnaa Aug 20 '19 at 10:20
-
It does not work well. https://github.com/syrusakbary/validate_email/issues/93 https://github.com/syrusakbary/validate_email/issues/109 – Vladimir May 24 '20 at 19:18
-
1@Vladimir I've updated the answer to include the new package which seems to be more supported https://pypi.org/project/py3-validate-email/ (thanks @krishnaa) – philshem May 25 '20 at 06:16
-
having trouble with pyDNS please check this post https://stackoverflow.com/questions/41342551/error-installing-pydns/62371748#62371748 – A.HEDDAR Jun 14 '20 at 11:18
-
Before discarding the "email_validator" package ( https://pypi.org/project/email-validator/ ) I think it's prudent to have a look here ( https://stackabuse.com/validate-email-addresses-in-python-with-email-validator/ ) and here ( https://pythonhosted.org/TurboMail/chapters/detailed.html ). There is another Python package (built-in "email") that can also solve the problem ( https://kalunite.net/parsing-email-addresses-in-python.html ). But if you really want to use Regex, this is the way ( https://stackoverflow.com/a/74925719/3223785 ). – Eduardo Lucio Dec 27 '22 at 17:26
-
I opted for "email_validator" because it has a more sophisticated and realistic implementation and provides facilities such as out-of-the-box domain validation. – Eduardo Lucio Dec 27 '22 at 17:27
-
Another cool reference ( https://morioh.com/p/c72092113c59 ) about "email_validator" package. – Eduardo Lucio Dec 27 '22 at 18:20
Email addresses are not as simple as they seem! For example, Bob_O'Reilly+tag@example.com, is a valid email address.
I've had some luck with the lepl package (http://www.acooke.org/lepl/). It can validate email addresses as indicated in RFC 3696: http://www.faqs.org/rfcs/rfc3696.html
Found some old code:
import lepl.apps.rfc3696
email_validator = lepl.apps.rfc3696.Email()
if not email_validator("email@example.com"):
print "Invalid email"

- 24,226
- 19
- 100
- 173

- 788
- 4
- 11
-
15
-
3For a simple use case like this, if the current version works the fact it's discontinued is not very relevant. – Vinko Vrsalovic Jul 04 '13 at 17:32
-
1this method doesn't work when u put email email''sfsf@sadasdas.adsdsa.com.com' It return true for this username too – Awesome Dec 29 '17 at 09:09
-
It seems to return False for everything I tried it with, valid or not. – Asclepius Mar 14 '19 at 01:16
I found an excellent (and tested) way to check for valid email address. I paste my code here:
# here i import the module that implements regular expressions
import re
# here is my function to check for valid email address
def test_email(your_pattern):
pattern = re.compile(your_pattern)
# here is an example list of email to check it at the end
emails = ["john@example.com", "python-list@python.org", "wha.t.`1an?ug{}ly@email.com"]
for email in emails:
if not re.match(pattern, email):
print "You failed to match %s" % (email)
elif not your_pattern:
print "Forgot to enter a pattern!"
else:
print "Pass"
# my pattern that is passed as argument in my function is here!
pattern = r"\"?([-a-zA-Z0-9.`?{}]+@\w+\.\w+)\"?"
# here i test my function passing my pattern
test_email(pattern)

- 2,332
- 11
- 33

- 205
- 4
- 10
-
3The only answer here I see here. That checks for characters allowed in [RFC 6531](https://tools.ietf.org/html/rfc6531) email standards. – edlee Jun 29 '17 at 20:51
-
-
1Copy web https://www.learnpython.org/en/Regular_Expressions .. only a problem 3rd email is wrong, its invalid cannot special character. – KingRider Feb 18 '20 at 11:43
-
4This pattern does not allow the underscore character in email addresses. – Alex Lach Mar 10 '20 at 13:44
I see a lot of complicated answers here. Some of them, fail to knowledge simple, true email address, or have false positives. Below, is the simplest way of testing that the string would be a valid email. It tests against 2 and 3 letter TLD's. Now that you technically can have larger ones, you may wish to increase the 3 to 4, 5 or even 10.
import re
def valid_email(email):
return bool(re.search(r"^[\w\.\+\-]+\@[\w]+\.[a-z]{2,3}$", email))

- 1,054
- 10
- 13
-
2
-
7
-
3
-
will this validate emails such as `user@department.company.com` (because it has 2 dots in the domain name part) ? – Mobigital Dec 25 '18 at 19:26
-
1
from validate_email import validate_email
is_valid = validate_email('example@example.com',verify=True)
print(bool(is_valid))
See validate_email docs.

- 10,713
- 1
- 52
- 62

- 79
- 1
- 4
-
1This library is buggy and has been giving a lot of false negatives, causing headache. – j4hangir Jun 11 '22 at 19:58
-
This is typically solved using regex. There are many variations of solutions however. Depending on how strict you need to be, and if you have custom requirements for validation, or will accept any valid email address.
See this page for reference: http://www.regular-expressions.info/email.html

- 7,522
- 3
- 20
- 38
Email addresses are incredibly complicated. Here's a sample regex that will match every RFC822-valid address: http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html
You'll notice that it's probably longer than the rest of your program. There are even whole modules for Perl with the purpose of validating email addresses. So you probably won't get anything that's 100% perfect as a regex while also being readable. Here's a sample recursive descent parser: http://cpansearch.perl.org/src/ABIGAIL/RFC-RFC822-Address-2009110702/lib/RFC/RFC822/Address.pm
but you'll need to decide whether you need perfect parsing or simple code.

- 10,531
- 2
- 36
- 55
-
According to this documentation ( https://pythonhosted.org/TurboMail/chapters/detailed.html ) "the original format for email messages was defined in RFC 822 which was superseded by RFC 2822. The newest standard document about the format is currently RFC 5322.". So, using something based on RFC 822 valid? – Eduardo Lucio Dec 27 '22 at 04:23
import re
def email():
email = raw_input("enter the mail address::")
match = re.search(r'[\w.-]+@[\w.-]+.\w+', email)
if match:
print "valid email :::", match.group()
else:
print "not valid:::"
email()

- 359
- 1
- 3
- 13
-
1Nice one - I think, though, the "." before the TLD needs to be escaped as "\." – Simon Steinberger Nov 23 '14 at 21:31
If you want to take out the mail from a long string or file Then try this.
([^@|\s]+@[^@]+\.[^@|\s]+)
Note, this will work when you have a space before and after your email-address. if you don't have space or have some special chars then you may try modifying it.
Working example:
string="Hello ABCD, here is my mail id example@me.com "
res = re.search("([^@|\s]+@[^@]+\.[^@|\s]+)",string,re.I)
res.group(1)
This will take out example@me.com
from this string.
Also, note this may not be the right answer... But I have posted it here to help someone who has specific requirement like me

- 1,345
- 1
- 8
- 23

- 61
- 1
- 6
For check of email use email_validator
from email_validator import validate_email, EmailNotValidError
def check_email(email):
try:
v = validate_email(email) # validate and get info
email = v["email"] # replace with normalized form
print("True")
except EmailNotValidError as e:
# email is not valid, exception message is human-readable
print(str(e))
check_email("test@gmailcom")

- 1,202
- 2
- 19
- 36
-
It may be helpful to understand the "practical" intent of this package: "This library validates that a string is of the form name@example.com. This is the sort of validation you would want for an email-based login form on a website." – dat Feb 13 '21 at 18:50
-
18Generally, answers, *especially* to regex-related questions, are much more helpful if they include a fairly detailed explanation of what the code or regex is intended to do, and why that solves the problem without introducing others. This is still more important with something that is as frankly error-prone and fiddly as email address validation; I've seen at least one regex that was **a full page long** for the purpose, and that was *without* insignificant whitespace. – Nathan Tuggy Feb 11 '15 at 00:20
-
This appears to be helpful: `return re.search("^[\w\.\+\-]+\@[\w]+\.[a-z]{2,3}$", email) != None` – Vladimir May 24 '20 at 19:20
Found this to be a practical implementation:
^[^@\s]+@[^@\s]+\.[^@\s]+$

- 607,720
- 39
- 448
- 563

- 3,646
- 3
- 31
- 37
-
1`[^@\s]+@[^@\s]+\.[^@\s]+` This is wrong because this will allow spaces in the extension part `.c om` and spaces are not allowed in emails. – WayBehind Apr 17 '20 at 18:25
-
no it won't allow those spaces, that's why it the last part has the \s. example: re.findall(r'[^@\s]+@[^@\s]+\.[^@\s]+', 'john@smith.this has spaces') = ['john@smith.this'] – juan Isaza Apr 20 '20 at 16:26
-
1EDIT: I was using `r.match` and `re.compile` to test, not `re.findall` so perhaps, we are both correct if used as intended. Unfortunately, you did not provide any details in your answer, and therefore, it was open to misunderstanding. If you edit your answer, I will be able to remove the downvote. Unfortunately, without your answer edit, the system will not let me to change my vote. – WayBehind Apr 20 '20 at 19:21
Finding Email-id:
import re
a=open("aa.txt","r")
#c=a.readlines()
b=a.read()
c=b.split("\n")
print(c)
for d in c:
obj=re.search(r'[\w.]+\@[\w.]+',d)
if obj:
print(obj.group())
#for more calcification click on image above..

- 15
- 4
-
Please edit the code so the indentation is correct, remove the line numbers and press ctrl + K with the code selected to format it. – Athena Aug 09 '17 at 12:05
Use this filter mask on email input:
emailMask: /[\w.\-@'"!#$%&'*+/=?^_
{|}~]/i`

- 19
- 3
email validation
import re
def validate(email):
match=re.search(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9]+\.[a-zA-Z0-9.]*\.*[com|org|edu]{3}$)",email)
if match:
return 'Valid email.'
else:
return 'Invalid email.'

- 773
- 6
- 17

- 33
- 1
The only really accurate way of distinguishing real, valid email addresses from invalid ones is to send mail to it. What counts as an email is surprisingly convoluted ("John Doe" <john.doe@example.com>"
actually is a valid email address), and you most likely want the email address to actually send mail to it later. After it passes some basic sanity checks (such as in Thomas's answer, has an @
and at least one .
after the @
), you should probably just send an email verification letter to the address, and wait for the user to follow a link embedded in the message to confirm that the email was valid.

- 151,563
- 33
- 264
- 304