Of all the input to validate, e-mail addresses seem to be one of the trickiest. At first glance, you might try validating the address with a simple regular expression, based on the usual requirements of an email provider. Let’s say two or more characters followed by an ‘@’ sign, followed by two or more characters, then a period and two or more characters. Two characters seems to be a good lower limit, because of addresses like ‘email@example.com’ or ‘firstname.lastname@example.org’. But here’s where problems start to crop up.
If we specified only alphanumeric characters, plus maybe an underscore, a domain like “.co.uk” would fail, or only return “email@example.com”. We could add an optional part to the TLD regex to allow domains like that, but it looks like we’ve forgotten about users like “firstname.lastname@example.org”. So maybe we should go back and expand the username portion as well. While we’re at it, we might as well incorporate all of the RFC spec, which results in something like this. While most mail clients (gmail, hotmail, etc) may not allow things like the plus sign (email@example.com), there are plenty of users out there who still use this for various reasons. When your validation is too strict, chances are you’ve overlooked something.
I won’t continue to drag on about the inadequacy of regular expressions in validating email addresses. If you’ve visited the RFC-compliant regular expression (which is a bit overkill, but illustrates the point nicely), you get the message. Time to move on.
So how can we make sure the user is entering a valid email address? Well, the most practical way would be to simply send them an email. Sanitize the input, and fire off a validation email with a “confirm account” link. No worries about regular expressions, no frustrated users with odd email addresses, and no fake emails. If you’re on a shared host that limits the amount of emails you can send, you could try stripping the domain off of the email and validating the domain before sending. This should stop emails like “firstname.lastname@example.org” from getting through, but will pass along “email@example.com”. You can do this with the following bit of code:
$is_valid = (filter_var($email, FILTER_VALIDATE_EMAIL)) ? checkdnsrr(substr(strrchr($email, "@"), 1),"MX") : false;