Validate emails in Laravel forms
A Laravel validation rule that fails an email address that cannot receive email, in any form request or Validator::make call. It is built on the official PHP client library, checks each address once, and never stops a real person from signing up when the API cannot answer in time.
use EmailValidation\Laravel\ValidEmail;
$request->validate([
'email' => ['bail', 'required', 'email', new ValidEmail()],
]);Install
The package is not on Packagist yet. Download it here and install it from a folder of your app:
Download email-validation-laravel-0.1.0.zip and save it in a folder of your project, for example
packages/.Add that folder as a Composer repository and require the package:
composer config repositories.email-validation-laravel artifact ./packages composer require email-validation/laravel:^0.1Composer installs the PHP client library from Packagist. Laravel discovers the service provider by itself.
Create an API key on the API keys page with the permission "Validate addresses", and give it a daily credit cap to limit what a busy form can spend, and put the form's route behind Laravel's
throttlemiddleware: each new address a visitor sends is a paid check. Put the key in.env:EV_API_KEY=your-api-keyThe key is read from your configuration only; never put it in code.
It needs Laravel 10 or newer and PHP 8.1 or newer.
Use the rule
Add the rule object, or the string rule, after Laravel's own email rule. With bail, a malformed address stops at email and is never sent.
'email' => ['bail', 'required', 'email', new ValidEmail()],
// fail disposable addresses too, and refuse the form when the check cannot finish
'email' => ['bail', 'required', 'email', new ValidEmail(failOn: ['invalid', 'disposable'], failOpen: false)],
// the string rule: the project's settings, or the failing statuses as parameters
'email' => 'bail|required|email|valid_email',
'email' => 'bail|required|email|valid_email:invalid,disposable',Settings
Publish the settings to config/email-validation.php to change them:
php artisan vendor:publish --tag=email-validation-config'api_key' => env('EV_API_KEY'),
'base_url' => env('EV_BASE_URL', 'https://api.email-validation.org'),
'fail_on' => ['invalid'],
'block_disposable' => (bool) env('EV_BLOCK_DISPOSABLE', false),
'fail_open' => (bool) env('EV_FAIL_OPEN', true),
'timeout' => 5,
'client_timeout' => 8,
'cache_store' => env('EV_CACHE_STORE'),
'cache_ttl' => 3600,- Which statuses fail. Only
invalidby default. SetEV_BLOCK_DISPOSABLE=trueto faildisposableaddresses as well.catch_allandunknownpass unless you add them: see what each status means. - When the check cannot finish (it timed out, the API could not be reached, it answered with a 5xx or 429 error, the account has no credits or no key is set), the address passes and a warning goes to your log with the error code and request id, never the address. Set
EV_FAIL_OPEN=falseto fail the field with "We could not check the email right now" instead. - EU data residency. Set
EV_BASE_URL=https://api-eu.email-validation.org; the same key works on both.
Speed and caching
The rule gives the API 5 seconds for the check (the API takes 5 to 15) and waits 8 seconds for the answer, without retrying: a slow mail server then answers unknown, which passes and is free.
Each result is kept in your cache for an hour, under a SHA-256 hash of the trimmed, lower-cased address, so a form sent again after fixing another field is not checked or charged again. Only the status is kept, never the address, and unknown results are not kept.
Messages
The messages are in the translation namespace email-validation. Publish them to change or translate them:
php artisan vendor:publish --tag=email-validation-langA message for one form, such as 'email.valid_email' => 'Please use another address.', also works with the string rule. The messages never show the API's own error text.
Costs
Each completed check costs one credit. Results with the status unknown are free, and so are malformed addresses and the test addresses: try the rule with accepted@sandbox.email-validation.org (passes) and no_mailbox@sandbox.email-validation.org (fails) at no cost. See credits and billing.
Related
- Validating sign-up forms: what to block and what to accept
- The PHP client library for other calls, such as bulk lists