email

Validates an email address, optionally layering rfc, strict, dns, spoof or filter checks.

Signature
email:rfc,dns

Parameters

ParameterTypeDescription
$validatorsoptionalstring= rfcA comma-separated list of validation styles: rfc, strict, dns, spoof, filter or filter_unicode. Any number may be combined and all must pass.

Errors

The dns and spoof styles require the PHP intl extension; without it the underlying validator cannot run.

Changelog

  • PHP 11.xAdded the fluent Rule::email() builder with rfcCompliant(), validateMxRecord() and preventSpoofing().

The field under validation must be formatted as an email address. The rule delegates to the egulias/email-validator package. By default only RFCValidation is applied; the other styles are opt-in.

StyleValidatorChecks
rfcRFCValidationConformance to the supported RFCs. The default.
strictNoRFCWarningsValidationThe same, but also fails on warnings such as trailing periods and consecutive periods.
dnsDNSCheckValidationThe domain has a valid MX record.
spoofSpoofCheckValidationNo homograph or deceptive Unicode characters.
filterFilterEmailValidationPHP's filter_var accepts it.
filter_unicodeFilterEmailValidation::unicode()As above, allowing some Unicode.

Choosing a combination

Plain email is right for most forms. Add dns only where a bad address is genuinely costly, because it performs a live MX lookup on every request — slow, dependent on the network, and something you will want to stub in tests. dns and spoof both require the PHP intl extension.

Validating format never proves the mailbox exists. For that, send a verification link.

Example

Example · php
<?php

use Illuminate\Support\Facades\Validator;

$value = '[email protected].';   // trailing period: an RFC "warning"

// Default rfc style: warnings are tolerated.
var_dump(Validator::make(['email' => $value], ['email' => 'email'])->passes());

// strict style: warnings become failures.
var_dump(Validator::make(['email' => $value], ['email' => 'email:strict'])->passes());

// bool(true)
// bool(false)

When to use it

  • Checking a sign-up form's email field before creating an account.
  • Rejecting typo domains at registration by adding the dns style.
  • Blocking homograph lookalike addresses on a security-sensitive form with spoof.
  • Matching a legacy system's laxer expectations by using the filter style.

Frequently asked questions

Does the email rule check that the address actually exists?

No. Even `email:dns` only confirms the domain publishes an MX record — it says nothing about whether the mailbox is real. The only reliable check is sending a verification link, which is what Laravel's MustVerifyEmail contract is for.

Which email validation style should I use?

Plain `email` for almost everything. Add `dns` only when a bogus address is genuinely expensive, and accept the latency and network dependency that comes with it. Use `strict` if you want trailing or consecutive periods rejected, and `spoof` on security-sensitive forms.

Why does email:dns fail in my test suite?

Because it performs a real DNS lookup, and test environments are usually offline or firewalled. Keep `dns` out of the rules used in tests, or apply it conditionally based on the environment so unit tests exercise the format check only.

More examples

The fluent Rule::email() builder

The builder reads better than a comma-separated flag list once you are combining three or more styles, and `strict: false` makes the rfc-versus-strict choice explicit rather than implied by which token you typed. Both forms produce the same underlying validators.

Example · php
<?php

use Illuminate\Validation\Rule;

$validated = $request->validate([
    'email' => [
        'required',
        Rule::email()
            ->rfcCompliant(strict: false)
            ->validateMxRecord()
            ->preventSpoofing(),
    ],
]);

echo $validated['email'];

// Equivalent to the string form 'required|email:rfc,dns,spoof'

Registration rules: format, uniqueness and confirmation together

This is the standard shape of a registration rule set. `max:255` guards the varchar column, `unique:users` checks the address is unused, and note that `password_confirmation` never appears in `validated()` because no rules were attached to it.

Example · php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'confirmed', 'min:8'],
        ];
    }
}

// print_r($request->validated());
//
// Array
// (
//     [name] => Taylor
//     [email] => [email protected]
//     [password] => correct-horse-battery
// )

Comparing the styles against the same inputs

The middle two rows are the documented difference between rfc and strict: trailing periods and consecutive periods are warnings under RFCValidation but hard failures under NoRFCWarningsValidation. The last row shows that a dotless domain is RFC-valid — add `dns` if you want it rejected.

Example · php
<?php

use Illuminate\Support\Facades\Validator;

$addresses = [
    '[email protected]',
    '[email protected].',
    '[email protected]',
    'taylor@localhost',
];

foreach ($addresses as $address) {
    $rfc    = Validator::make(['e' => $address], ['e' => 'email'])->passes();
    $strict = Validator::make(['e' => $address], ['e' => 'email:strict'])->passes();

    printf("%-28s rfc=%-5s strict=%s\n",
        $address,
        var_export($rfc, true),
        var_export($strict, true)
    );
}

// [email protected]           rfc=true  strict=true
// [email protected].          rfc=true  strict=false
// [email protected]   rfc=true  strict=false
// taylor@localhost             rfc=true  strict=true

Discussion

  • Be the first to comment on this lesson.