mattketmo/email-checker
PHP library that validates email addresses beyond a simple regex: it checks RFC compliance and DNS MX records, and can connect to the SMTP server to confirm the mailbox actually exists. Framework-agnostic, so it drops into any PHP or Laravel app.
Architecture fit. mattketmo/email-checker is a framework-agnostic, Composer-installed PHP library that answers one question: is this email address from a disposable/temporary provider? It has no Laravel coupling, no database, no queue, and no outbound network calls — it is a pure in-process lookup against a bundled domain list (with separate handling for wildcard domains where any subdomain is disposable). Architecturally this is a "domain service in the validation layer," so it slots in cleanly beside Laravel's built-in email rule with no conflict. The adapter abstraction (ArrayAdapter, JsonFileAdapter, ChainAdapter) is the extension seam we would build against, since it lets us swap the data source (bundled JSON → our own refreshed list → a commercial API) without touching call sites.
Integration feasibility. High. composer require mattketmo/email-checker, bind a singleton in a service provider, wrap in a custom Rule object, and attach it to the relevant FormRequests. Realistic effort: 1–2 engineering days including unit tests and a feature test on the registration path. There is no Laravel service provider shipped, so we own that glue (the upstream Symfony bundle is a reasonable reference for wiring patterns but should not be pulled in).
Technical risk.
Key questions.
Stack fit. Laravel 9–12, PHP 8.1+. Verify PHP 8.x compatibility explicitly before adoption (the library's lineage predates PHP 8; the recent release date suggests it is maintained, but confirm the CI matrix). No new infrastructure: no Redis, no queue worker, no external HTTP dependency, and therefore no new GDPR/data-processor surface — email addresses never leave the process, which is a meaningful compliance advantage over API-based verification vendors.
Migration path. Greenfield for most teams: nothing to migrate. If a homegrown regex or hardcoded domain blacklist already exists, introduce the package behind our own DisposableEmailDetector interface, implement it with the package, and swap the old implementation out behind a feature flag. That interface is the real deliverable — it is what makes a future switch to a commercial vendor or a fork a one-file change.
Compatibility.
ArrayAdapter/PhpArrayAdapter loaded once per worker over JsonFileAdapter parsed per request, especially under Octane where a warm singleton persists.email rule — compose them: syntax check first (cheap), disposable check second (cheap), DNS/MX check last (network).Sequencing.
DisposableEmailDetector interface, implement with the package, add a config file for policy (enabled, fail-open, allowlist of our own partner domains), write unit tests including a corrupt-file case.Maintenance. Low code maintenance, moderate data maintenance. Budget roughly a recurring half-day per month for: reviewing upstream releases, refreshing the domain list, and re-checking the false-positive metric. Treat the domain list as configuration we own — snapshot it, version it, and serve it from a path we control so a package update is never the only path to fresher data. Watch the upstream repo for abandonment signals (no release in >6 months, unanswered issues) and keep a fork ready; MIT means the fork is cheap.
Support. This is "vendor-lite": no commercial support, one maintainer, thin docs, but a small and readable API surface — a mid-level engineer can read the whole thing in an hour. The real support burden is user-facing: blocked registrations generate support tickets. Provide a documented allowlist mechanism and an internal runbook for "legitimate user blocked" that a support agent can execute without engineering.
Scaling. Effectively free. The check is an O(1) hash lookup against a list in the low thousands of domains — sub-millisecond, no I/O after load, no per-request allocation if bound as a singleton. The only scaling pitfall is instantiating the checker per request in a high-QPS path (JSON parse per request) or under Octane where a naive per-request construction wastes cycles; both are solved by singleton binding. Memory footprint is a few hundred KB per worker.
Failure modes.
Ramp-up. Hours, not days. The API is small, the integration is idiomatic Laravel, and there is no operational surface to learn. The genuine ramp-up cost is organizational, not technical: agreeing the blocking policy, defining the false-positive tolerance, and assigning an owner for the domain-list refresh cadence. That governance work is the actual gate on shipping this — the code is the easy part.
TPM recommendation. Adopt, but as one layer in a layered validation strategy and behind our own interface, gated on an observe-only period with a measured false-positive rate. The package is cheap, low-risk, and privacy-friendly; the two things that determine whether it succeeds are data freshness ownership and an explicit fail-open policy — both of which are decisions we make, not properties of the library.
How can I help you explore Laravel packages today?