Regan Johnson - Web Design, Marketing, SEO

Validate e-mail addresses using PHP

As a PHP programmer, there are a lot of people in this world that piss me off - collectively I label them as spammers! About.com estimates there are 183 billion e-mails sent every day in the world, with over 70% being considered spam - Hell, no wonder why my internet bill is getting to be so expensive!

When building new scripts or applications, I am always looking for new ways to increase security and the quality of my user generated content (such as member profiles, posts, comments, etc). There is nothing more frustrating than having an excellent web application that is littered with spam.

The process I use to determine if an e-mail address is legitimate

There are a few steps in the process that I use to validate an e-mail address which, together, are built for speed and accuracy. I encourage you to decide which steps you would like to use in your script, as they can also be used separate from each other.

Before we get started, I wanted to note that these functions are not intended to be comprehensive, as we are only checking the domain for MX records, and not the individual e-mail on that domain (which is a bit more complicated then the intentions of this tutorial). With that being said these functions will help narrow down the verification process significantly!

Filter improperly formatted e-mail addresses

This step is a good, quick brush to make sure that the e-mail address is in the proper format. I recommend including this step at a minimum - using PHP’s built in RegEx function, preg_match.

The function

function verify_email($email){

    if(!preg_match('/^[_A-z0-9-]+((\.|\+)[_A-z0-9-]+)*@[A-z0-9-]+(\.[A-z0-9-]+)*(\.[A-z]{2,4})$/',$email)){
        return false;
    } else {
        return $email;
    }
}

Because this article is not about regular expression, I am only going to provide a brief explanation about what’s going on here. Basically, you would call this function (example below) passing in an e-mail address whose format you wish to validate. The regular expression checks that the proper parts of an e-mail address are in the correct places, contain the correct characters, and are the correct lengths - if the e-mail is not formatted correctly, it will return false.

How to use it

$email = 'test@domain.com';

if(verify_email($email)){
    echo 'Success - E-mail address appears to be valid';
} else {
    echo 'Error - E-mail address appears to be invalid';
}

// sdasda@asdasd.com - true
// asdasd$%@.faa.ca.ds - false

While this function will flag some blatant examples of spam, you will notice that some pretty spammy looking e-mails will make it past this step which isn’t all that great But don’t worry, we actually test the domain in the following step.

Check the DNS of the e-mail’s domain to make sure it has a proper MX Record

For those of you who don’t know, and MX Record is a piece of data on a domain name that tells other computers and servers what to do when someone sends an e-mail address to that domain. By checking to see if an MX Record exists using PHP, we are taking the e-mail verification one step farther - a check that the domain actually exists and it’s able to host e-mail boxes. We will accomplish this using another one of PHP’s built in functions, checkdnsrr.

The function

function verify_email_dns($email){

    // This will split the email into its front
    // and back (the domain) portions
    list($name, $domain) = split('@',$email);

    if(!checkdnsrr($domain,'MX')){

        // No MX record found
        return false;

    } else {

        // MX record found, return email
        return $email;

    }
}

When using this function, PHP will send a call to the domain of the e-mail address you are attempting to validate, and check its MX records. If they are present and valid, it will return true, otherwise it will return false - simple as that!

How to use it

$email = 'test@domain.com';

if(verify_email_dns($email)){
    echo 'Success - E-mail has a valid MX record';
} else {
    echo 'Error - E-mail does not have an MX record';
}

// omg@omgomgomgeh.com - false
// steve@apple.com - true

Putting it all together

Now that we have our functions, and some working examples, let’s put it all together to be one badass e-mail validation function.

Example

$email = 'test@domain.com';

if(verify_email($email)){

    // E-mail address looks to be in the proper format
    // lets check the MX records

    if(verify_email_dns($email)){

        // E-mail passed both checks
        echo 'Success - E-mail address appears to be valid.';

    } else {

        // E-mail is invalid, no MC record
        echo 'Error - E-mail domain does not have an MX record.';

    }

} else {

    // E-mail inst formatted correctly
    // so we don't even check its MX record
    echo 'Error - E-mail address appears to be invalid.';

}

// Our function to filter our bogus formatted addresses
function verify_email($email){

    if(!preg_match('/^[_A-z0-9-]+((\.|\+)[_A-z0-9-]+)*@[A-z0-9-]+(\.[A-z0-9-]+)*(\.[A-z]{2,4})$/',$email)){
        return false;
    } else {
        return $email;
    }
}

// Our function to verify the MX records
function verify_email_dns($email){

    // This will split the email into its front
    // and back (the domain) portions
    list($name, $domain) = split('@',$email);

    if(!checkdnsrr($domain,'MX')){

        // No MX record found
        return false;

    } else {

        // MX record found, return email
        return $email;

    }
}

There you have it folks! A nifty little function to help keep your user base clean, and spam free! It’s important to note that the lookup of a domain names MX Record in this manner is currently only supported on Unix based systems - Sorry Windows.

Extend it into your own projects

This post is a start to integrating and building these functions into your own projects. For example, On some personal projects, I have taken these functions even farther. Because the MX Record checks takes a second or two to complete, I developed a system to cache results that come back as positive in a database for quick access of common domain names.

Have fun experimenting! As always, if you have any questions, I would love to hear them, and will do my best to help you out!

Update

I changed the verify_email() function above to use preg_match instead of eregi for the regular expression. This method is much faster. Someone pointed out to me that the regex was not updated for allowing “+” within the address, something that is starting to catch on. I have made the changes, and tested things out. Thanks for pointing this out to me.

24 people have left comments

Ella - Gravatar

Ella said:

Thanks for adding support for the “john+smith@gmail.com” e-mail variety.

Posted on: April 9, 2008 at 3:00 amQuote this Comment
Pierluigi - Gravatar

Pierluigi said:

Mmmhh,
it’s better to write:

if(!eregi(”^[_a-z0-9-]+(\.[_a-z0-9-]+)*@
[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$”, $email))

all on a line:

if(!eregi(”^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$”, $email))

or some people will try with a valid email address and will receive an error ;)

Posted on: April 9, 2008 at 3:43 amQuote this Comment
Jad - Gravatar

Jad said:

gr8 script i will try to develop it into a script that validate my forum’s registration emails.

Posted on: April 9, 2008 at 6:25 amQuote this Comment
loreto - Gravatar

loreto said:

Thank you for this great tutorial, even though i havent tested this yet but i feel confident. Thanks again, i’ll try this later and have some experiements. :)

Posted on: April 9, 2008 at 7:18 amQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

Pierluigi said: Mmmhh,
it’s better to write:
if(!eregi(…….

Good catch! I split it up to fit on the page, as that regex was a bit long! Thanks for pointing this out to me.

Posted on: April 9, 2008 at 8:50 amQuote this Comment
Mewp - Gravatar

Mewp said:

A suggestion for speed improvements

1. Quoting from php.net: “Note: preg_match(), which uses a Perl-compatible regular expression syntax, is often a faster alternative to ereg(). “.

I’ve done an quick benchmark for you:
100k iterations of eregi (with your regex): 2.25695300102
100k iterations of preg_match (with your regex surrounded by “/” and “/i”): 1.17411780357
If I’d change ” to ‘, it would be 1.90202188492 for eregi and 0.757380008698 for preg_match.

Posted on: April 9, 2008 at 9:13 amQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

Mewp said: A suggestion for speed improvements

1. Quoting from php.net:

Thanks for the comment. I do agree that preg_match offers some speed advantages. I will rework the function.

Posted on: April 9, 2008 at 9:46 amQuote this Comment
dgm - Gravatar

dgm said:

There’s more to a valid email than that. If you look at the RFC for email, it’s a lot more complicated. Google for a perl regex for email, it’s huge.

Posted on: April 9, 2008 at 11:51 amQuote this Comment
User Game Reviews - Gravatar

User Game Reviews said:

I am a php programmer also. Whenever I used to do contact forms eventually they got spammed hard. The most effective method I have found so far without a doubt is checking for “http://” in any of the fields. If this is found at all then it detects it as spam and doesn’t let it through. Obviously you could have exceptions for fields that are suppose to have a web address listed, but for most contact forms, no one needs to be putting a link in it. For most of the sites I have done this to, it eliminates the spam completely and it is a very very simple method.

Posted on: April 9, 2008 at 1:38 pmQuote this Comment
Ikaro - Gravatar

Ikaro said:

Great! It’s exactly what i was looking for. Thanks!
Dan

Posted on: April 10, 2008 at 9:28 amQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

dgm said: There’s more to a valid email than that. If you look at the RFC for email, it’s a lot …

I will do some more research, thanks dgm.

Ikaro said: Great! It’s exactly what i was looking for. Thanks!
Dan

No worries, thanks for checking out my blog! :D

Posted on: April 10, 2008 at 10:21 amQuote this Comment
Muzicar - Gravatar

Muzicar said:

Great functions ;) Every single developer needs such. Great work. Stumbled :)

Posted on: April 29, 2008 at 5:52 pmQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

Muzicar said: Great functions ;) Every single developer needs such. Great work. Stumbled :)

Thanks a lot, Muzicar! I am working on a more robust version of this that will be even more comprehensive and comply with the full standard.

Posted on: April 29, 2008 at 5:56 pmQuote this Comment
Nate - Gravatar

Nate said:

Good stuff
STUMBLED

Posted on: May 7, 2008 at 5:01 pmQuote this Comment
Mazri - Gravatar

Mazri said:

Good word. I like php but sometime i make me to cry. Haha

Posted on: May 29, 2008 at 9:27 pmQuote this Comment
Mark Olsen - Gravatar

Mark Olsen said:

We use this function (slightly rewritten for simplicity) in every single homepage we publish. Thanks!

Posted on: June 10, 2008 at 8:34 amQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

Mark Olsen said: We use this function (slightly rewritten for simplicity) in every single homepage we publish. Thanks!

Thanks a lot for letting me know! I am glad I could be of some help! Keep on programming!

Posted on: June 10, 2008 at 9:01 amQuote this Comment
Ryan - Gravatar

Ryan said:

It would help to mention (unless I missed it) that checkdnsrr() is *not* implemented on Windows. Thankfully php.net was the first thing I checked after my script returned an error.

Posted on: June 18, 2008 at 1:09 pmQuote this Comment
Ryan - Gravatar

Ryan said:

Sorry, I saw that you did mention that right after I posted. My apologies.

Posted on: June 18, 2008 at 1:10 pmQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

Ryan said: Sorry, I saw that you did mention that right after I posted. My apologies.

Not a problem Ryan. Thank you for keeping an eye out though. There is a workaround for Windows machines involving fsock. I will post a follow up to include this. Take care.

Posted on: June 18, 2008 at 3:19 pmQuote this Comment
Eneza - Gravatar

Eneza said:

Great! Nice Tutorial you have there my lad….. thanks for the INFO

Posted on: August 4, 2008 at 9:48 pmQuote this Comment
missfitbit - Gravatar

missfitbit said:

Ummm…noob question:

Where exactly do I put this? In the php the form posts to? In a separate php as a class? derrrr. Sorry. I’m sure that’s a really dumb question and shows just how in over my head I am…

Thanks anyway!

Posted on: August 22, 2008 at 4:55 pmQuote this Comment
Scott F - Gravatar

Scott F said:

Thanks a lot for helping us fight spam!!!!!

Posted on: August 24, 2008 at 12:29 amQuote this Comment
Regan Johnson - Gravatar

Regan Johnson said:

missfitbit said: Ummm…noob question:

Where exactly do I put this? In the php the form posts to? In a separate php as …

The easiest way to include this into your application would be to copy and paste the above code into your script, and then call the functions as needed to validate e-mail addresses (usually on a POST). If you need to use these functions on multiple pages, you can include the functions in a global function file.

Hope this helps!

Posted on: August 24, 2008 at 12:16 pmQuote this Comment

Leave a Comment-

Comment Guidelines: Basic XHTML is allowed (a href, strong, em, code). All line breaks and paragraphs are automatically generated. Off-topic or inappropriate comments will be edited or deleted. Email addresses will never be published. Keep it PG-13 people!

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

All fields marked with "*" are required.