Laravel · PHP

Block disposable email in Laravel

Create a custom validation rule and attach it to your RegisterRequest or Fortify/Breeze signup form.

The code

<?php
// app/Rules/NotDisposableEmail.php
namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Http;

class NotDisposableEmail implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try {
            $response = Http::timeout(5)
                ->withToken(config('services.piisend.key'))
                ->post('https://api.piisend.com/api/v1/intelligence/email', ['email' => $value]);

            if ($response->successful() && ($response->json('signals.disposable') === true)) {
                $fail('Please use a permanent email address.');
            }
        } catch (\Throwable $e) {
            // fail open
        }
    }
}

// app/Http/Requests/RegisterRequest.php
public function rules(): array
{
    return [
        'email' => ['required', 'email', new \App\Rules\NotDisposableEmail],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
    ];
}

API key

Add `piisend.key` to `config/services.php` from `PIISEND_API_KEY` env.

Fail-open vs fail-closed

Empty catch allows signup on outage — log exceptions in production.

Pair with verification

Works with Laravel Fortify, Breeze, or Jetstream register controllers.

Send verification email with Piisend

After blocking disposable addresses, send OTP and verification mail through the same Piisend account. One API key for intelligence checks and transactional sends.