Check signup emails in Laravel
This guide adds a Signitize validation rule to a Laravel (10 or later) registration form. It uses Laravel's HTTP client, so no package is needed.
1. Add your key
.env
SIGNITIZE_API_KEY=sk_live_...
config/services.php
'signitize' => [
'key' => env('SIGNITIZE_API_KEY'),
],
Get a free key if you don't have one.
2. The column
database/migrations/xxxx_add_email_check_to_users.php
Schema::table('users', function (Blueprint $table) {
$table->string('email_canonical')->nullable()->unique();
$table->string('email_check')->default('pending');
});
3. The rule
app/Rules/SignitizeEmail.php
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class SignitizeEmail implements ValidationRule
{
/** The Signitize result, or null when the check was unavailable. */
public ?array $result = null;
public function validate(string $attribute, mixed $value, Closure $fail): void
{
try {
$response = Http::withToken(config('services.signitize.key'))
->timeout(5)
->post('https://api.signitize.io/v1/check', ['email' => $value]);
} catch (ConnectionException) {
return; // timeout or network error: don't block the signup
}
if ($response->status() === 400) {
$fail('Enter a valid email address.');
return;
}
if (! $response->ok()) {
Log::warning('Signitize unavailable', ['status' => $response->status()]);
return;
}
$this->result = $response->json();
if ($this->result['disposable']) {
$fail('Please use a permanent email address.');
} elseif (! $this->result['deliverable']) {
$fail('This email address cannot receive mail. Please check it for typos.');
}
}
}
4. The controller
app/Http/Controllers/RegisterController.php
use App\Models\User;
use App\Rules\SignitizeEmail;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
public function store(Request $request)
{
$emailRule = new SignitizeEmail();
$data = $request->validate([
'name' => ['required', 'string', 'max:100'],
'email' => ['required', 'string', 'max:254', $emailRule],
'password' => ['required', 'confirmed', 'min:8'],
]);
$canonical = $emailRule->result['email'] ?? null;
if ($canonical && User::where('email_canonical', $canonical)->exists()) {
throw ValidationException::withMessages(['email' => 'You already have an account.']);
}
$user = User::create([
'name' => $data['name'],
'email' => trim($data['email']),
'email_canonical' => $canonical,
'email_check' => $canonical ? 'passed' : 'pending',
'password' => $data['password'],
]);
$user->sendEmailVerificationNotification();
// ...log in and redirect as usual
}
The verification email goes to the typed address. With Laravel Breeze or Jetstream, add $emailRule to the email rules of the existing registration code instead.
5. Recheck pending users
Users created while Signitize was unavailable are pending. Schedule a command every 10 minutes (Schedule::command(...)->everyTenMinutes()) that runs the recheck logic from Never block a signup, and grant free credits only to passed users.