Skip to content

[11.x] Add fluent Email validation rule - #54067

Merged
taylorotwell merged 7 commits into
laravel:11.xfrom
SanderMuller:Add-Rule-email()
Jan 9, 2025
Merged

[11.x] Add fluent Email validation rule#54067
taylorotwell merged 7 commits into
laravel:11.xfrom
SanderMuller:Add-Rule-email()

Conversation

@SanderMuller

Copy link
Copy Markdown
Contributor

This PR aims to provide a similar experience as the Password validation rule and File validation rule (#43271) for emails. It does so by providing a fluent, extendable Email rule object.

Basic usage

// Before
$request->validate([
  'email' => ['required', 'string', 'email', 'strict', 'dns'],
]);
 
// After
$request->validate([
  'email' => ['required', 'string', Rule::email()->strict()->dns()],
]);

Available methods

The following methods are available on the rule:

  • ::default: equivalent to the Password::default() rule
  • ::strictSecurity: equivalent to Rule::email()->strict()->dns()->spoof()
  • strict: equivalent to the strict rule
  • dns: equivalent to the dns rule
  • spoof: equivalent to the spoof rule
  • filter: equivalent to the filter rule
  • filterUnicode: equivalent to the filter_unicode rule
  • rfc: equivalent to the rfc rule

Extending for custom types

Whilst the File rule only ships with the ::image method as a custom type, the rule is Macroable, allowing each application to specify more granular file permissions as required.

// AppServiceProvider
public function boot()
{
  Email::macro('employee', function () {
    return Email::default()->rules('ends_with:@laravel.com');
  });
}

// Usage
$request->validate([
  'email' => ['required', Email::employee()->spoof()]
]);

Open for discussion

I've added strictSecurity method as an option to easily create a solid email validation check, since the differences between the available rules are rather complex. Not including this method would be a valid choice as well. However, I hope this method will help Laravel developers better secure the email inputs, for example example against spoofing. The composition of this methods (strict + DNS + spoof) is a result of running applications in production and handling all kinds of edge cases with invalid emails that passed validation before using this combination.

Thanks to @lukeraymonddowning for providing #43271. I've used his PR as inspiration for the body text of this PR.

@github-actions

github-actions Bot commented Jan 3, 2025

Copy link
Copy Markdown

Thanks for submitting a PR!

Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

*
* @param static|callable|null $callback
* @return static|null
* @return static|void

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

never returns null, but does return void

use Illuminate\Validation\Validator;
use PHPUnit\Framework\TestCase;

class ValidationEmailRuleTest extends TestCase

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Test class inspired by ValidationFileRuleTest

use Stringable;
use function Illuminate\Support\enum_value;

class Email implements Rule, DataAwareRule, ValidatorAwareRule

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Heavily inspired by src/Illuminate/Validation/Rules/File.php

@SanderMuller
SanderMuller marked this pull request as ready for review January 3, 2025 11:58
Comment thread src/Illuminate/Validation/Rules/Password.php
Comment thread src/Illuminate/Validation/Rules/File.php
Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
@taylorotwell

Copy link
Copy Markdown
Member

While I like terse methods, I wonder if we should give these methods a bit more descriptive names? It's not super clear was spoof or dns means when chaining them together.

@taylorotwell
taylorotwell marked this pull request as draft January 3, 2025 15:52
@SanderMuller

SanderMuller commented Jan 3, 2025

Copy link
Copy Markdown
Contributor Author

While I like terse methods, I wonder if we should give these methods a bit more descriptive names? It's not super clear was spoof or dns means when chaining them together.

@taylorotwell Thank you for reviewing the pull request and providing your feedback. I’ve updated the method names to make them more descriptive and aligned with Laravel’s validation conventions.

New names:

rfcCompliant(): Ensures compliance with RFC standards.
rfcCompliant(true): Adheres strictly to RFC without warnings (formerly strict).
nativeFilter(): Validates email format using FILTER_VALIDATE_EMAIL.
nativeFilter(true): Extends basic format validation to include Unicode support.
verifyMxRecord(): Verifies that the domain has a valid MX record.
preventEmailSpoofing(): Detects and prevents email spoofing.

I attempted to pick names aiming to balance clarity and brevity, ensuring developers can intuitively understand the intent of each rule when chaining them together. For example:

Rule::email()
    ->rfcCompliant(true)
    ->domainExists()
    ->preventEmailSpoofing();

Perhaps they are not perfect yet, but it might inspire you to make the final naming tweaks!

@SanderMuller
SanderMuller marked this pull request as ready for review January 3, 2025 17:31
@SanderMuller

Copy link
Copy Markdown
Contributor Author

@taylorotwell If we’re moving away from string-based names, we could also consider @shaedrich’s suggestion of merging the rfcCompliant and rfcCompliantWithoutWarnings rules into a single rule, such as rfcCompliant(bool $strict). Similarly, combining basicFormat and basicFormatWithUnicode into basicFormat(bool $withUnicode) would simplify things, since these are essentially variants of each other.

This approach would reduce the number of methods from 6 to 4, making the API easier to use and more intuitive while maintaining clarity.

Let me know your thoughts!

Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
@shaedrich

Copy link
Copy Markdown
Contributor

rfcCompliant: Ensures compliance with RFC standards.
rfcCompliantWithoutWarnings: Adheres strictly to RFC without warnings (formerly strict).

I would actually flip that negation around:
rfcCompliantWarningsAllowed: Ensures compliance with RFC standards.
strictRfcCompliance: Adheres strictly to RFC without warnings (formerly strict).

Comment thread src/Illuminate/Validation/Rules/Email.php Outdated
@taylorotwell
taylorotwell merged commit 832ebc0 into laravel:11.x Jan 9, 2025
@SanderMuller
SanderMuller deleted the Add-Rule-email() branch January 10, 2025 14:02
@taylorotwell

Copy link
Copy Markdown
Member

@SanderMuller would you mind sending over some documentation for this?

@SanderMuller

Copy link
Copy Markdown
Contributor Author

@SanderMuller would you mind sending over some documentation for this?

Will work on it 👍

@SanderMuller

Copy link
Copy Markdown
Contributor Author

@SanderMuller would you mind sending over some documentation for this?

@taylorotwell done via laravel/docs#10112, let me know what you think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants