Validates an email address, optionally layering rfc, strict, dns, spoof or filter checks.
email:rfc,dnsParameters
| Parameter | Type | Description |
|---|---|---|
$validatorsoptional | string= rfc | A 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.
| Style | Validator | Checks |
|---|---|---|
rfc | RFCValidation | Conformance to the supported RFCs. The default. |
strict | NoRFCWarningsValidation | The same, but also fails on warnings such as trailing periods and consecutive periods. |
dns | DNSCheckValidation | The domain has a valid MX record. |
spoof | SpoofCheckValidation | No homograph or deceptive Unicode characters. |
filter | FilterEmailValidation | PHP's filter_var accepts it. |
filter_unicode | FilterEmailValidation::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
<?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.
<?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.
<?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.
<?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