kcassam/mailcheck
MailCheck for Laravel/PHP validates email addresses by checking domain/MX records, disposable and role-based accounts, helping reduce bounces and spam signups. Includes a configurable validation rule for easy form integration.
Install the package with Composer and let Laravel's package discovery register it:
composer require kcassam/mailcheck
First places to look:
Headoo/mailcheck) — it is the only reliable source for the exact class name, facade alias, and return shape. With 6 stars and 0 dependents there is very little community documentation, so treat the source src/ directory as the API reference.composer.json for extra.laravel.providers. If discovery is not configured, add the provider to config/app.php.php artisan vendor:publish --provider="Kcassam\\Mailcheck\\MailcheckServiceProvider") and inspect the static domain list. That list is the package's entire behavior model.The canonical first use case is a registration/checkout form suggestion: the user types [email protected], your endpoint returns [email protected], and the UI shows a non-blocking "Did you mean…?" prompt. This is the same behavior as the JavaScript mailcheck.js library, just executed server-side.
A minimal smoke test in tinker:
app(\Kcassam\Mailcheck\Mailcheck::class)->check('[email protected]');
// expect a suggestion object/array containing the corrected domain
Get that working before wiring anything into forms — the package is small enough that confirming one call is enough to validate the install.
Wrap it in your own service. Because the package is thin and unmaintained-looking, isolate it behind an application service so you can swap in mailcheck.js or a DNS-based checker later without touching controllers:
namespace App\Services;
use Kcassam\Mailcheck\Mailcheck;
class EmailSuggestionService
{
public function __construct(private Mailcheck $mailcheck) {}
public function suggest(string $email): ?string
{
$email = strtolower(trim($email));
$result = $this->mailcheck->check($email);
if (! $result) {
return null;
}
// Normalize whatever shape the package returns (array or object).
$suggestion = is_array($result) ? ($result['full'] ?? null) : ($result->full ?? null);
return $suggestion && $suggestion !== $email ? $suggestion : null;
}
}
Expose it as a small JSON endpoint rather than calling the package from Blade. This keeps the suggestion logic testable and lets you debounce on the client:
Route::post('/email/suggest', function (Request $request, EmailSuggestionService $service) {
$request->validate(['email' => ['required', 'email']]);
return response()->json([
'suggestion' => $service->suggest($request->string('email')),
]);
})->middleware('throttle:30,1');
Integrate with Form Requests as advisory feedback. Do not turn the suggestion into a hard validation failure. Validate email normally, then attach the suggestion to a redirect/flash or an Inertia prop:
public function store(StoreRegistrationRequest $request, EmailSuggestionService $service)
{
$suggestion = $service->suggest($request->validated('email'));
if ($suggestion && ! $request->boolean('confirmed_suggestion')) {
return back()->withInput()->with('email_suggestion', $suggestion);
}
// proceed with registration
}
Pair this with a hidden confirmed_suggestion field so the second submit goes through. This is the pattern that avoids the classic trap of blocking a legitimate user whose domain merely looks like a typo.
Client-side pattern. Trigger the endpoint on blur, not on every keystroke, and render the suggestion as a clickable link that rewrites the input. Works equally well with Alpine, Livewire (wire:blur), or a plain fetch.
Testing. Because the suggestion is deterministic against a static list, unit-test the service directly with the known good/bad pairs, then feature-test the HTTP endpoint and the "second submit passes" flow. A small it()-style test file here is worth more than mocking the package.
[email protected] gets no help and [email protected] may get a false suggestion. Never use it as your only email validation.trim() the address; mixed-case input and trailing spaces will skew the distance calculation or bypass the match entirely.@headoo.com isn't "corrected" to @yahoo.com-style output.mail.example.co.uk). Filter suggestions where the corrected string differs by more than a small edit distance, or skip when the input domain already resolves.[email protected]) should be preserved in the suggested address — verify the package doesn't strip them, and reconstruct the local part yourself if it does.blur endpoint is a free request amplifier on a public registration page.app(Mailcheck::class)) or constructor injection; only add a facade alias if the README documents one.illuminate/support constraint in composer.json against your Laravel version before installing. With 0 dependents there is no crowd confirming it works on the latest framework, so run the smoke test in CI before merging.mailcheck.js is the mature upstream of this idea and gives you instant client-side feedback with no round trip. If the PHP package's return shape or maintenance becomes friction, the JS library plus a thin server-side fallback is a common production compromise.How can I help you explore Laravel packages today?