Laravel Email Validation: be aware of how you validate

If you have already worked with Laravel validation then you should know that it has an email validation rule with the next validators: rfc, strict, dns, spoof, filter. But in Laravel documentation, there is a poor explanation of these validators. I want you to know a bit deeper about how each of them validates.

Laravel utilizes the egulias/EmailValidator package for validating an email address in all validators except filter. This library aims to support these RFCs: 5321, 5322, 6530, 6531, 6532, 1035. Need to say that the package author made a big work to create one, especially when delving into those RFCs. Do try to read and understand what is written there because it is dangerous for your brain, I have wracked mine 🙂

RFC Validation (rfc and strict)

This is the default Laravel email validation from Laravel version 5.8. So validation rules shown below are the same:

'email' => 'email'
'email' => 'email:rfc'

If you will review RFC specs you will see that email address format can contain double quotes, folding whitespaces, comments(strings of characters enclosed in parentheses), backslashes, and others. I will not immerse you into these rules, but I will provide a few examples of email addresses that will pass this validation:

And there is more. Doesn’t look like valid email addresses from popular email providers in 2021, right? If you want to exclude most of them and leave only email formats that in a broader interpretation are accepted then you should use this strict validation. For example, only these emails from the list above will pass strict validation:

DNS Check Validation (dns)

This email validation checks if the email address domain exists or is configured to receive emails. It gets all MX, A and AAAA DNS records for the host, and then it will count email address as valid if MX records exist and its target is not empty or if A and/or AAAA DNS records exist.

Let’s think about it. If a domain has A and/or AAAA records then we can consider that this domain exists. It is not about fake email addresses because users can just write a fake email address with the domain of popular email providers and pass validation. This check can be useful if we want the user not to make a typo in the domain part of the email. Next, if a domain has MX records and its target is not empty then it means that the domain is configured to receive emails. All I want to say is that this validation does not prove both of these checks. Furthermore, this email validation does not prove that email address really exists even if both checks are passed.

To summarize DNS check validation, I would like to say that this email validation is not strict, and in my projects, I would prefer to split this validation into two using custom validation rules, and if needed to check email address really exists then I would prefer to implement email verification.

To use this validation PHP intl extension should be installed.

Spoof Check Validation (spoof)

This validation is used to prevent email spoofing. Email spoofing is when an attacker imitates a trusted email address or domain by changing letters or numbers to appear only slightly different than the original. For example, [email protected] and info@paypаl.com look like the same email addresses. But really I changed letter a to а. You can check it by searching on this page one of these emails and you will see that only one email matches.

So this validation checks if all characters of the email are from a single script. It uses the native PHP class Spoofchecker and as DNS check validation also requires PHP intl extension to be installed.

Filter Email Validation (filter)

This validation uses the native PHP function filter_var with FILTER_VALIDATE_EMAIL filter and FILTER_FLAG_EMAIL_UNICODE flag. It was the default email validation in Laravel versions older than 5.8. As written in PHP manual, this validates against email address syntax in RFC 822 with the exception that comments(strings of characters enclosed in parentheses) and whitespace folding and dotless domain names are not supported. For example, these emails from the list above will not pass filter validation:

Custom Email Validation Rules

In Laravel, you can create your own validation rules. You can make it quite easily by calling Artisan command. For example, let’s create a validation rule which checks if the email address is a Gmail email address. Let’s create rule:

php artisan make:rule GmailValidation  

This command will create rule file in app/Rules directory. Open it and add your validation logic to the passes() method:

public function passes($attribute, $value)
{
    $domainPart = explode('@', $value)[1] ?? null;

    if (!$domainPart) {
        return false;
    }

    if ($domainPart != 'gmail.com') {
        return false;
    }

    return true;
}

And also add an error message to the message() method:

public function message()
{
    return 'The :attribute must be a Gmail address';
}

And then add this rule to your validation request:

'email' => [new GmailValidation()]