aman00323/emailchecker
EmailChecker for Laravel validates email addresses beyond basic format checks, using DNS and MX lookups plus disposable, role-based, and free-provider detection to catch typos and risky addresses before they hurt deliverability. Configurable and easy to integrate into registration or lead forms.
Install into the Laravel app:
composer require aman00323/emailchecker
Laravel's package auto-discovery should register the service provider. If the facade isn't aliased automatically, add it to config/app.php (or use the fully-qualified class name directly).
Publish config if offered, then review it before writing code:
php artisan vendor:publish --tag=emailchecker-config
Look for flags controlling which checks run (syntax, MX/DNS, disposable-domain list, role accounts, SMTP probe) and any timeout values. Start with the cheapest checks enabled and add SMTP only if you control the outbound network.
Smoke-test in tinker before wiring it into a flow. Facade/method names vary between releases, so confirm the exact signature in the README and dump the result object:
use Aman00323\EmailChecker\Facades\EmailChecker;
$result = EmailChecker::check('[email protected]');
dd($result); // inspect isValid(), isDisposable(), reason, etc.
First use case: registration. Wrap it in a custom validation rule and attach it to your RegisterRequest:
class RegisterRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => ['required', 'string', 'email', new VerifiedEmail()],
];
}
}
That's the minimum viable integration: install → config → tinker → validation rule. Everything else is refinement.
Custom validation rule with a configurable failure policy. Don't hardcode "reject disposable" in the rule. Read the policy from config so you can loosen it in production without a deploy:
class VerifiedEmail implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$result = EmailChecker::check($value);
if (! $result->isValid() && config('emailchecker.strict')) {
$fail('This email address could not be verified.');
}
if ($result->isDisposable() && config('emailchecker.block_disposable')) {
$fail('Please use a permanent email address.');
}
}
}
Wrap the package behind your own contract. This is the single highest-value pattern for a small, single-maintainer dependency:
interface EmailVerifier
{
public function verify(string $email): EmailVerdict;
}
Bind the package-backed implementation in a service provider. Your controllers, rules, and jobs depend on EmailVerifier, not the vendor facade — swapping to Kickbox/ZeroBounce or Laravel's built-in email:rfc,dns later becomes a one-file change.
Never block registration on expensive checks. A synchronous SMTP handshake can take seconds and will dominate your registration latency. Instead: validate syntax + MX inline, create the user, and dispatch a queued job for the deeper checks:
RegisterUser::dispatch($user);
// job calls EmailVerifier, sets $user->email_risk = 'disposable'
Cache aggressively. Email verification is deterministic for a given address over short horizons. Cache by hash, not plaintext:
$key = 'email-check:'.hash('sha256', strtolower($email));
$verdict = Cache::remember($key, now()->addDays(30), fn () => $this->verifier->verify($email));
Bulk imports. For CSV imports, use Bus::batch() with chunked jobs and RateLimiter (or ->delay()/->middleware('throttle')) so you don't hammer DNS resolvers. Cache MX results per domain — a 10k-row import usually touches a few hundred domains, not 10k.
Surface results in the UI without hard failures. A debounced endpoint returning { valid, disposable, suggestion } lets you show "Did you mean gmail.com?" or a soft warning on checkout, rather than a validation error the user can't act on.
Testing. Mock the facade or your own EmailVerifier in feature tests so the suite never makes real DNS calls; keep a small integration test group that hits the real package and is excluded from CI by default.
warning, and let the request through — a bounce is cheaper than a lost signup.php artisan config:cache, any env() calls outside the package's config file return null. Make sure the package's config file actually reads env vars and isn't reading them at runtime.composer.json, watch the issue tracker, and keep the interface wrapper as your escape hatch.email:rfc,dns rule covers syntax + MX validation. Adopt this package specifically for disposable-domain and role-account detection — that's where it adds value over the framework.How can I help you explore Laravel packages today?