Tutorial: PHP Email Address Validator

GithubIf you find this tutorial and code useful, please take a moment to star it on Github. If you want to help develop it further, fork it.

I bet every developer who is reading this tutorial is starting off with the premise that email address validation is easy and they have a one-liner that does the job. And that probably is true. I say probably because most developers assume an email address being in a recognizable format is all it takes to be considered valid. But if the company’s success is tied to email marketing and bogus email addresses are accepted because they meet that simple criteria, is your email validation really doing its job? Confirming that a user can receive emails at the email address they provided, and that they can continue to do so for a reasonable time after their interaction with your website, is a far better validation for said email marketing company that something that looks to be correct.

The Email Validator library builds upon PHP’s built in filter_var($emailAddress, FILTER_VALIDATE_EMAIL); by adding a default MX record check. It also offers additional validation against disposable email addresses, free email address providers, and a custom banned domain list.

Be sure to read Going Deeper into Email Address Validation to have a better understanding of the complexities of email validation.

Requirements

  • PHP 7.2 or newer

Installation

To add PHP Email Validation to your project, add a dependency on stymiee/email-validator to your project’s composer.json file if you use Composer to manage the dependencies of your project. Here is a minimal example of a composer.json file that just defines a dependency on PHP Email Validation:

"require": {
    "stymiee/email-validator": "^1"
}

Including it in your project is then as simple as including your vendor autoload file:

require('./vendor/autoload.php');

Features

The PHP Email Validator will validate an email address for all or some of the following conditions:

  • is in a valid format
  • has configured MX records (optional)
  • is not a disposable email address (optional)
  • is not a free email account (optional)
  • is not a banned email domain (optional)

The Email Validator is configurable, so you have full control over how much validation will occur.

Available Validations

  • Validate MX

    If checkMxRecords is set to true in the configuration (see below) the domain name will be validated to ensure it exists and has MX records configured. If the domain does not exist or no MX records exist the odds are the email address is not in use.

  • Restrict Disposable Email Addresses

    Many users who are abusing a system, or not using that system as intended, can use a disposable email service who provides a short-lived (approximately 10 minutes) email address to be used for registrations or user confirmations. If checkDisposableEmail is set to true in the configuration (see below) the domain name will be validated to ensure it is not associated with a disposable email address provider.

    You can add you own domains to this list if you find the public list providers do not have one you have identified in their lists.

  • Restrict Free Email Address Providers

    Many users who are abusing a system, or not using that system as intended, can use a free email service who provide a free email address which is immediately available to be used for registrations or user confirmations. If checkFreeEmail is set to true in the configuration (see below) the domain name will be validated to ensure it is not associated with a free email address provider.

    You can add you own domains to this list if you find the public list providers do not have one you have identified in their lists.

  • Restrict Banned Domains

    If you have users from a domain abusing your system, or you have business rules that require the blocking of certain domains (i.e. public email providers like Gmail or Yahoo mail), you can block then by setting checkBannedListedEmail to true in the configuration (see below) and providing an array of banned domains.

Validated email addresses are checked against a list of known disposable and free email address providers (depending upon your configuration) which are aggregated from public disposable email address provider lists. This requires making HTTP requests to get the lists when validating the address.

Basic Usage

To use the Email Validator you need to configure it to validate according to your business rules. You can enable or disable checks and provide your own disposable email list and free domain lists providers as well as your own banned list. You then call the validate() method on the email address you wish to validate.

Configuration

Email Validator takes an optional array of boolean key/value pairs which enable/disable package functionality. It also takes optional arrays of domains which can be provided to further filter email addresses based on specific criteria.

  • checkMxRecords

    A boolean value that enables/disables MX record validation. Enabled by default.

  • checkBannedListedEmail

    A boolean value that enables/disables banned domain validation. Disabled by default.

  • checkDisposableEmail

    A boolean value that enables/disables disposable email address validation. Disabled by default.

  • checkFreeEmail

    A boolean value that enables/disables free email address provider validation. Disabled by default.

  • localDisposableOnly

    A boolean value that when set to true will not retrieve third party disposable email provider lists. Use this if you cache the list of providers locally which is useful when performance matters. Disabled by default.

  • localFreeOnly

    A boolean value that when set to true will not retrieve third party free email provider lists. Use this if you cache the list of providers locally which is useful when performance matters. Disabled by default.

  • bannedList

    An array of domains that are not allowed to be used for email addresses.

  • disposableList

    An array of domains that are suspected disposable email address providers.

  • freeList

    An array of domains that are free email address providers.

Below are some sample configurations.

Using default settings

// No configuration is passed to the EmailValidator Constructor
$emailValidator = new EmailValidator();

Validating against disposable and free email provider lists (no caching)

$config = [
    'checkDisposableEmail' => true,
    'checkFreeEmail' => true,
];
$emailValidator = new EmailValidator($config);

Disposable email list with custom domains

$customDisposableEmailList = [
    'example.com',
];
$config = [
    'checkDisposableEmail' => true,
    'disposableList' => $customDisposableEmailList,
];
$emailValidator = new EmailValidator($config);

Simple Example

$emailValidator = new EmailValidator();
$emailIsValid = $emailValidator->validate('user@example.com');

A More Robust Example

use EmailValidator\EmailValidator;
 
require('../vendor/autoload.php');
 
$customDisposableEmailList = [
    'example.com',
];
$customFreeEmailList = [
    'example2.com',
];
$bannedDomainList = [
    'domain.com',
];
 
$testEmailAddresses = [
    'test@johnconde.net',
    'test@gmail.com',
    'test@hotmail.com',
    'test@outlook.com',
    'test@yahoo.com',
    'test@domain.com',
    'test@mxfuel.com',
    'test@example.com',
    'test@example2.com',
    'test@nobugmail.com',
    'test@cellurl.com',
    'test@10minutemail.com',
];
 
$config = [
    'checkMxRecords' => true,
    'checkBannedListedEmail' => true,
    'checkDisposableEmail' => true,
    'checkFreeEmail' => true,
    'bannedList' => $bannedDomainList,
    'disposableList' => $customDisposableEmailList,
    'freeList' => $customFreeEmailList,
];
$emailValidator = new EmailValidator($config);
 
foreach($testEmailAddresses as $emailAddress) {
    $emailIsValid = $emailValidator->validate($emailAddress);
    echo ($emailIsValid) ? 'Email is valid' : $emailValidator->getErrorReason();
    echo PHP_EOL;
}

Outputs:

Email is valid
Domain is used by free email providers
Domain is used by free email providers
Domain is used by free email providers
Domain is used by free email providers
Domain is banned
Domain is used by disposable email providers
Domain is used by free email providers
Domain is used by disposable email providers
Domain does not accept email
Domain is used by disposable email providers
Domain is used by disposable email providers
    

Caching Remote Content

Some of the features of the Email Validator require retrieving files from Github. The files contain lists of disposable or free email address providers and are regularly updated. However, retrieving and parsing these lists for every email address is both slow and unnecessarily repetitive. Although these lists are regularly updated, that frequency is in terms of days and not minutes or hours. A list retrieved an hour ago is still valid and accurate the most likely are few or no new records added since you last retrieve that list.

If you plan to take advantage of this functionality it is recommended that you cache these lists and refresh them periodically. Once per day during low volume of usage should be sufficient. The code below shows how you can get these lists

use EmailValidator\Policy;
use EmailValidator\Validator\DisposableEmailValidator;
 
require('../vendor/autoload.php');
 
$disposableEmailList = (new DisposableEmailValidator(new Policy()))->getList();
$freeEmailList = (new FreeEmailValidator(new Policy()))->getList();

$disposableEmailList and $freeEmailList each contain an array of domains, disposable and free email providers respectively, that you can store in memory for faster access. You then can use these cached copies of those lists without making HTTP calls by configuring the Email Validator to use only your local copies.

$config = [
    'localDisposableOnly'=> true,
    'localFreeOnly' => true,
    'disposableList' => $customDisposableEmailList,
    'freeList' => $customFreeEmailList,
];
$emailValidator = new EmailValidator($config);

Help & Support

If you require assistance using this library start by viewing the HELP.md file included in this package. It includes common problems and their solutions.

If you continue to have difficulty using this code please do not contact me through this website. Since this software is free to the community, the community can assist me in supporting it. I am an active participant at Stack Overflow. Others also frequent it who are also capable of assisting you with this code. When posting your question there, or anywhere for that matter, be sure to include the following:

  • A link to either this article and/or the GitHub repository so others can see what software you are using and can download it if necessary so if they attempt to reproduce the problem you are having.
  • Your code as it is implemented in your software. Make sure you format it so it is readable by others.
  • A description of what you are expecting your code to do (but it is not happening).
  • Any error message you are getting.

Leave a Reply

Your email address will not be published. Required fields are marked *