Block disposable email signups in Laravel
Add a custom rule class. The rule runs as part of Laravel's validator, so disposable emails surface as standard form errors with no extra plumbing.
The code
<?php
// app/Rules/NotDisposable.php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class NotDisposable implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
try {
$res = Http::withToken(config('services.cde.key'))
->timeout(3)
->get('https://api.checkdisposable.email/v1/check', ['email' => $value]);
if ($res->successful() && $res->json('is_disposable') === true) {
$fail('Please use a real email address.');
}
} catch (\Throwable $e) {
Log::warning('CDE unreachable, failing open', ['error' => $e->getMessage()]);
}
}
}
// app/Http/Controllers/Auth/RegisteredUserController.php
public function store(Request $request)
{
$request->validate([
'email' => ['required', 'email', new \App\Rules\NotDisposable],
'password' => ['required', 'min:8'],
]);
// ...create user
}Notes
- config/services.php
- Add `'cde' => ['key' => env('CDE_KEY')]` so the rule reads through Laravel's typed config rather than hitting env() at runtime.
- Fortify / Breeze / Jetstream
- For Fortify, add the rule via the `Fortify::createUsersUsing` action. For Breeze and Jetstream, the rule drops into the existing Validator config without further work.
- Inertia + Vue
- Failed validation surfaces in the inertia errors bag, so the disposable message renders alongside other field errors without special handling on the frontend.
Get a free API key
500 checks/month, no credit card. No credit card. 30 seconds.
Sign up free →