Quick links: Source code | Email address validators head-to-head
There’s a gazillion regular expressions out there that claim to validate an email address. They don’t. Doug Lovell explains why here. The function that Doug made for his article is good, but it delegates the validation of the domain part of the address to the DNS servers of the world. This is a good approach but there are three issues with it:
- The RFCs reluctantly allow you to use an IP address rather than a domain name, so you need to check for that.
- The DNS may not be available to your function at the time it needs to check the address (maybe it’s an intranet application)
- There’s no need to add extra workload to the DNS servers of the world if the address is wrongly formatted in the first place.
So I’ve come up with a PHP function that validates all parts of a given email address, according to RFCs 1123, 2396, 3696, 4291, 4343, 5321 & 5322. I’ve released it under a license that allows you to use it royalty-free in commercial or non-commercial work, subject to a few conditions (Doug Lovell’s function is All Rights Reserved by Linux Journal so you can’t use it for anything).
It’s almost certainly the first email address validator that correctly lets you put an IPv6 address in for the domain part…
I’ve also included a lot of unit tests, including all Doug Lovell’s examples and all the examples of valid addresses in RFC 3696. You might try running these test past your current email address validator. Prepare for the same nasty surprise I got :-)
The source code is available here.





This is really sweet Dominic; Thank You!
I am having a problem understanding why .comt and other inappropriate tld’s are considered valid. syntactically, they meet the criteria, but that’s not good enough. Is is best to simply use an array with all existing values. Not very maintainable. What are other thoughts about this?
Hi Scott,
There’s no authoritative source for a list of TLDs. The list doesn’t change much but I wonder how many people who implemented a validator 5 years ago now allow .museum?
С большинством Ваших постов я не согласен, но этот пост очень пришелся по душе :)
Hello Dominic,
I tested your code against the list of email addresses provided in Doug Lovell’s article. Your code does not accept all the addresses that Doug says are valid.
Those that are rejected by your code are:
abc\@def@example.com is not valid.
abc\\@example.com is not valid.
Fred\ Bloggs@example.com is not valid.
Joe.\\Blow@example.com is not valid.
Doug\ \”Ace\”\ Lovell@example.com is not valid.
Why do you think you code is refusing them? Are they valid as Doug claims?
Also, your code generated a number of PHP notices when I ran them using PHP 5.2.9
PHP Notice: Uninitialized string offset: 0 in /tmp/validEmail.php on line 131
PHP Notice: Uninitialized string offset: -1 in /tmp/validEmail.php on line 142
PHP Notice: Uninitialized string offset: 0 in /tmp/validEmail.php on line 285
PHP Notice: Uninitialized string offset: -1 in /tmp/validEmail.php on line 296
Those lines are:
131: if ($element[0] === ‘(‘) {
142: if ($element[$elementLength - 1] === ‘)’) {
285: if ($element[0] === ‘(‘) {
296: if ($element[$elementLength - 1] === ‘)’) {
When $elementLength has a value of zero (0), the lines 142 and 296 are trying to get the character at position -1. That position cannot exist in a string.
Changing the lines like this would be better I think:
131: if (isset($element[0]) && $element[0] === ‘(‘) {
142: if ($elementLength > 0 && isset($element[$elementLength - 1]) && $element[$elementLength - 1] === ‘)’) {
285: if (isset($element[0]) && $element[0] === ‘(‘) {
296: if ($elementLength > 0 && isset($element[$elementLength - 1]) && $element[$elementLength - 1] === ‘)’) {
What do you think?
Hi Christian and thanks for the feedback. I’ll work on getting rid of those PHP notices for the next version.
The addresses that Doug says are valid are not valid! He was citing addresses from the original version of RFC 3696. This RFC was later corrected by its author (see the errata here: http://www.rfc-editor.org/errata_search.php?rfc=3696&eid=246)
Unfortunately the RFC online system only shows you the original version not the corrected one. I’m sure this led Doug Lovell to make the mistakes he made in his article.
Very nice validator, thanks for going to the trouble of writing it. After seeing Doug Lovell’s article, I tested our existing email validators and found them to be deficient, so I was very happy to find your post here. It will save me a bit of time rewriting the validator from scratch :)
Thanks for the kind words, Brian.
Wish to hear a notification, so I can try it back sir, thank you
Hi Raghu,
I checked the code and the only problem I could find was that it was checking the DNS record even if you supplied a domain literal (e.g. first.last@[123.123.123.123]
Please would you try the latest version from Google Code and let me know if there is still a problem for you? Here is the download location: http://code.google.com/p/isemail/source/browse/trunk
D.
Dear Dominic
thanks for the nice code.
I am actually on your website from http://www.linuxjournal.com/article/9585 after seeing your link in the comment.
I am surprised to see and know that many different symbols can be alowed in the email address. That code didnot work for me.
So I tried your code, it showed 1, and when I checked with an echo statement, it ECHOED outcome in TEXT.
I am happy to see email validation is successful for 4 lettered tld like .info, .name atlast.
Upon this success, I had enabled $checkDNS = true and tried an unexisting email address based on unexisting domain name, it still shows VALID
aahdshd@aasdfgfddjdjdjdjdjddj.info.in.co.in.co
getting to your notice, so, as this is fixed, with your permission, I wish to use this in our website, thank you
With Best Regards
Raghu Veer
Raghu,
I’ll check this out and update the code if necessary
D.
No problem Scott. You are helping me see this from an outside point of view, which is very useful.
Hi Dominic,
Thanks again, as you can tell I’m a php novice, but looking to learn all the time.
/* If e-mail is not valid show error message */
if (!is_email($email))
{
show_error(”E-mail address not valid”);
}
Hi Dominic,
Thanks for getting back to me so quickly.
Where exactly should I place ‘$valid = is_email ($email);’?
Here is a link to my source code:
http://www.glentechsolutions.co.uk/contact-test.php
As you can see I’ve got basic email validation:
/* If e-mail is not valid show error message */
if (!preg_match(“/([\w\-]+\@[\w\-]+\.[\w\-]+)/”, $email))
{
show_error(“E-mail address not valid”);
}
which I would like to replace with your code.
Hi Scott,
Looks like some of your comment got mangled. All you need to do to implement this is copy-and-paste the is_email function into your code (somewhere near the top) and then you can validate an email address like this:
$valid = is_email($email);
$valid will be either true or false depending on whether $email is a valid email address.
Hi Dominic,
This is exactly what I’m after :-)
This is my code so far, how do I implement your code into it?
I’m a PHP novice, so just getting to grips with things at the moment.
And this is at the end of my HTML:
Please correct the following error:
Many Thanks
Scott
This one’s pretty good though: http://simonslick.com/VEAF/Code/Verbose.txtThe SimonSlick code is actually proprietary so I shouldn’t properly include it here