RFC-compliant email address validator

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:

  1. The RFCs reluctantly allow you to use an IP address rather than a domain name, so you need to check for that.
  2. The DNS may not be available to your function at the time it needs to check the address (maybe it’s an intranet application)
  3. 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 112323963696429143435321 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.

Quick links: Source code | Email address validators head-to-head


19 Responses to “RFC-compliant email address validator”

  1. 1 Scott K. March 6, 2010 at 04:45

    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?

    • 2 Dominic Sayers March 6, 2010 at 19:50

      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?

  2. 3 Бaкинcкийпapeнь November 27, 2009 at 16:01

    С большинством Ваших постов я не согласен, но этот пост очень пришелся по душе :)

  3. 4 Christian Roy June 12, 2009 at 13:32

    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?

    • 5 Dominic Sayers June 15, 2009 at 08:08

      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.

  4. 6 Brian June 4, 2009 at 17:59

    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 :)

  5. 8 Raghu Veer March 12, 2009 at 08:03

    Wish to hear a notification, so I can try it back sir, thank you

  6. 10 Raghu Veer March 12, 2009 at 05:53

    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


    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

  7. 12 Dominic Sayers February 10, 2009 at 10:37

    No problem Scott. You are helping me see this from an outside point of view, which is very useful.

  8. 13 Scott February 9, 2009 at 23:09

    Hi Dominic,

    Thanks again, as you can tell I’m a php novice, but looking to learn all the time.

  9. 14 Dominic Sayers February 9, 2009 at 17:02

    /* If e-mail is not valid show error message */
    if (!is_email($email))

    show_error(”E-mail address not valid”);

  10. 15 Scott February 9, 2009 at 16:36

    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:


    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.

  11. 16 Dominic Sayers February 6, 2009 at 10:34

    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.

  12. 17 Scott February 6, 2009 at 10:12

    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


  13. 18 Dominic Sayers January 29, 2009 at 14:05

    This one’s pretty good though: http://simonslick.com/VEAF/Code/Verbose.txt The SimonSlick code is actually proprietary so I shouldn’t properly include it here

  1. 1   New and noteworthy open source email implementations | On Message with Ben Gross Trackback on June 19, 2009 at 21:45

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s


This is not a riot

RSS What Dominic is doing

  • An error has occurred; the feed is probably down. Try again later.

Share me

Add to Technorati Favorites

Dominic's photographs

RSS My stubbornly unread reading list

  • An error has occurred; the feed is probably down. Try again later.

%d bloggers like this: