Skip to content
189 changes: 189 additions & 0 deletions validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [Error Message Indexes and Positions](#error-message-indexes-and-positions)
- [Validating Files](#validating-files)
- [Validating Passwords](#validating-passwords)
- [Validating Emails](#validating-emails)
- [Custom Validation Rules](#custom-validation-rules)
- [Using Rule Objects](#using-rule-objects)
- [Using Closures](#using-closures)
Expand Down Expand Up @@ -1240,6 +1241,8 @@ The `filter` validator, which uses PHP's `filter_var` function, ships with Larav
> [!WARNING]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to link this:

- The `filter` validator, which uses PHP's `filter_var` function, ships with Laravel and was Laravel's default email validation behavior prior to Laravel version 5.8.
+ The `filter` validator, which uses PHP's [`filter_var` function](https://www.php.net/manual/en/filter.constants.php#constant.filter-validate-email), ships with Laravel and was Laravel's default email validation behavior prior to Laravel version 5.8.
 
[!WARNING]

> The `dns` and `spoof` validators require the PHP `intl` extension.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could link this:

Suggested change
> The `dns` and `spoof` validators require the PHP `intl` extension.
> The `dns` and `spoof` validators require the [PHP `intl` extension](https://www.php.net/manual/de/book.intl.php).


Since email validation can be quite complex, you may use [Rule::email()](#validating-emails) to fluently construct the rule.

<a name="rule-ends-with"></a>
#### ends_with:_foo_,_bar_,...

Expand Down Expand Up @@ -2241,6 +2244,192 @@ Occasionally, you may want to attach additional validation rules to your default
// ...
});

<a name="validating-emails"></a>
## Validating Emails

Laravel provides a variety of validation rules that may be used to validate uploaded files, such as `rfc`, `strict` and `dns`. While you are free to specify these rules individually when validating emails, Laravel also offers a fluent email validation rule builder that you may find convenient:
To ensure that emails are valid according to your application's requirements, you may use `Rule` class to fluently define the rule via ` Rule::email()`:

```php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$validator = Validator::make($request->all(), [
'email' => ['required', Rule::email()],
]);
```
The `Email` rule object allows you to easily customize how emails are validated for your application, such as specifying that emails require RFC compliance, DNS checks, or spoof detection:

```php
// Basic RFC compliance...
Rule::email()->rfcCompliant();

// Strict RFC compliance...
Rule::email()->rfcCompliant(strict: true);

// Check for valid MX records...
Rule::email()->validateMxRecord();

// Prevent spoofing...
Rule::email()->preventSpoofing();
```
Of course, you may chain all the methods in the examples above:

```php
Rule::email()
->rfcCompliant(strict: true)
->validateMxRecord()
->preventSpoofing();
```

> [!WARNING]
> The `validateMxRecord()` and `preventSpoofing()` validators require the PHP `intl` extension.

<a name="defining-default-email-rules"></a>
#### Defining Default Email Rules
You may find it convenient to specify the default validation rules for emails in a single location of your application. You can easily accomplish this using the Email::defaults method, which accepts a closure. The closure given to the defaults method should return the default configuration of the `Email` rule. Typically, the `defaults` rule should be called within the boot method of one of your application's service providers:

```php
use Illuminate\Validation\Rules\Email;

/**
* Bootstrap any application services.
*/
public function boot(): void
{
Email::defaults(function () {
$rule = (new Email())->rfcCompliant(strict: true)->preventSpoofing(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be ; instead of , at the end


return $this->app->isProduction()
? $rule->validateMxRecord()
: $rule;
});
}
```
Then, when you would like to apply the default rules to a particular email undergoing validation, you may invoke the defaults method with no arguments:

```php
'email' => ['required', Email::defaults()],
```
Occasionally, you may want to attach additional validation rules to your default email validation rules. You may use the rules method to accomplish this:

```php
Email::defaults(function () {
return (new Email())->rfcCompliant(strict: true)
->preventSpoofing()
->rules(['ends_with:@example.com']);
});
```

### Use Cases & Examples
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might alternatively be a table:

Method Description Use case example
rfcCompliant(strict: bool) Validates the email according to RFC 5322.
Passing true enforces stricter RFC checks (e.g., rejects invalid.@example.com).
Use rfcCompliant() if you need standard RFC validation while allowing some unusual formats.
Use rfcCompliant(true) if you want to reject less typical but technically valid addresses.
Basic RFC validation
Rule::email()->rfcCompliant();
Strict RFC validation
Rule::email()->rfcCompliant(true);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to add a link up there, where the string rule is explained:
#10112 (comment)


Each method on the `Email` rule addresses a different aspect of email validation.

#### `rfcCompliant(strict: bool)`

**What it does**
- Validates the email according to [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322).
- Passing `true` enforces stricter RFC checks (e.g., rejects trailing dots or multiple consecutive dots).

**When to use it**
- Use `rfcCompliant()` for typical RFC validation while allowing some uncommon formats.
- Use `rfcCompliant(true)` to reject unusual but technically valid addresses.

**Examples**
- **Addresses that pass on `rfcCompliant()` but fail on `rfcCompliant(true)`**
- `invalid.@example.com` (local part ends with a dot)
- `some..dots@example.com` (double dots in local part)
- **Address that fail on both**
- `test@example..com` (double dots in the domain part) typically fails in *both* modes.

**Example**
```php
// Basic RFC validation
Rule::email()->rfcCompliant();

// Strict RFC validation
Rule::email()->rfcCompliant(true);
```

#### `validateMxRecord()`

**What it does**
- Ensures the domain has a valid MX record so it can receive mail.

**When to use it**
- Especially useful for sign-ups, password resets, or anywhere deliverability matters.

> [!NOTE]
> This rule triggers DNS lookups, which adds latency to the request and can fail if the domain’s DNS is temporarily unreachable or down.

**Example**
```php
Rule::email()->validateMxRecord();
```

#### `preventSpoofing()`

**What it does**
- Detects homograph or deceptive Unicode usage (e.g., Cyrillic “р” vs. Latin “r”) to prevent phishing or impersonation.

**When to use it**
- Ideal in security-sensitive contexts or where email spoofing is a concern.

**Example**
```php
Rule::email()->preventSpoofing();
```

> [!NOTE]
> The `validateMxRecord()` and `preventSpoofing()` methods require the PHP `intl` extension.

#### `withNativeValidation(bool $allowUnicode = false)`

**What it does**
- Uses PHP’s `FILTER_VALIDATE_EMAIL` for validation.
- When `allowUnicode` is `true`, some Unicode characters are allowed.

**When to use it**
- If you want an additional layer of PHP’s built-in validation.
- Typically for ASCII addresses unless you explicitly allow Unicode.

*Comparing `withNativeValidation(true)` vs. `rfcCompliant(true)`*
- **`rfcCompliant(true)`** follows strict RFC rules, potentially rejecting addresses with unusual local parts or domain syntax.
- **`withNativeValidation(true)`** might allow some Unicode addresses that strict RFC rules would reject. For example:
- `"Name With Space"@example.com` could fail under strict RFC but pass native validation if quoted properly.
- `user@üñîçødé.com` might fail strict RFC but pass `withNativeValidation(true)`.

**Example**
```php
// Use native PHP validation (ASCII-only)
Rule::email()->withNativeValidation();

// Allow some Unicode
Rule::email()->withNativeValidation(true);
```

> [!NOTE]
> `withNativeValidation()` is **less strict** than RFC validation and was previously the default in Laravel. If you need strict RFC compliance, use `rfcCompliant(true)` instead.

### Combining Methods

You can **chain** multiple methods to cover various scenarios:

```php
$validator = Validator::make($request->all(), [
'email' => [
'required',
Rule::email()
->rfcCompliant(true) // Strict RFC validation
->validateMxRecord() // Requires valid MX record
->preventSpoofing() // Detects homograph attacks
],
]);
```

> **Note**
> If you want **less strict** RFC enforcement, omit `true` in `->rfcCompliant(true)`. If your application doesn’t require domain or spoof checks, you can remove those methods from the chain.

<a name="custom-validation-rules"></a>
## Custom Validation Rules

Expand Down