Latest version on Packagist Tests Static analysis License: MIT
Email utilities for Laravel — a fluent API over an address value object that parses correctly, from one address to a whole list: canonicalisation for deduplication, maintained disposable and role-account lists, a cached deliverability resolver, batch auditing and an opt-in HTTP API.
Targets PHP ^8.4.1 on Laravel ^13.
This package holds the data and the IO. The validation rules live in
laranail/validation and work without this package,
over small bundled fallbacks. Installing this one swaps in maintained lists and a production
resolver — through contracts, so no rule and no call site changes.
composer require laranail/email
Then schedule the refresh, because a frozen list decays quietly — it keeps working, it just stops catching anything new:
// routes/console.php Schedule::command('laranail::email.refresh-lists')->weekly();
use Simtabi\Laranail\Email\Facades\Mail as EmailAddress; $email = EmailAddress::of('Alice+Newsletter@Example.COM'); $email->localPart(); // 'Alice+Newsletter' — case preserved: local parts are case-sensitive $email->domain(); // 'example.com' — lowercased: domains are not $email->mailbox(); // 'Alice' $email->tag(); // 'Newsletter' $email->canonical(); // 'alice@example.com' — one form per mailbox, for deduplication $email->problems(); // everything wrong with it, at once
And for a list, which is how the job usually arrives:
$audit = EmailAddress::audit($csvColumn, checkReachability: true); $audit->summary(); // ['total' => 4200, 'usable' => 3910, 'duplicates' => 61, ...] $audit->problems(); // ['role_account' => 180, 'disposable' => 74] $audit->distinct(); // the rows to keep
And in free text, which is where addresses turn up when nobody put them in a field:
EmailAddress::find($supportTicket); // matches, with byte offsets EmailAddress::redact($supportTicket); // 'contact a••••@example.com now'
Reachability over a batch is resolved per domain, so ten thousand addresses at one provider cost one MX lookup rather than ten thousand.
The validation rules are unchanged and come from laranail/validation:
'email' => FluentRule::email()->required()->notDisposable()->notRole(), 'email' => ['required', 'email', new DeliverableEmail()],
Never make a DNS query in a test:
use Simtabi\Laranail\Email\Testing\FakeDnsResolver; use Simtabi\Laranail\Validation\Contracts\Email\DnsResolver; $dns = FakeDnsResolver::deliverable('example.com'); $this->app->instance(DnsResolver::class, $dns); // ... exercise the code ... expect($dns->wasAsked('example.com'))->toBeTrue();
Full documentation is at opensource.simtabi.com/documentation/laranail/email .
- Installation — install, publish, and schedule the refresh
- Getting started — parse, judge and deduplicate, end to end
- Configuration — four blocks, and the one that is a security decision
- Architecture — why the rules live in another package, and the binding asymmetry
- Release — versioning, tagging, and moving in step with
laranail/validation
- Fluent builder —
Mail::of(...), canonicalisation, and all the problems at once - Batch and audit — judging a whole list, per-domain reachability, and the queued job
- Scanner — finding addresses in free text, and what a match can honestly claim
- HTTP API — three endpoints, off by default, and how to turn them on safely
- Lists — disposable domains, role accounts, refreshing, and the fallback
- Resolver — caching, TTL asymmetry, and what a failed lookup means
- Deduplicate signups — one person, four addresses, one mailbox
- Audit a mailing list — judge a list before you send to it
- Audit a table in the background — a million rows on the queue
- Redact a support ticket — take the addresses out of text you are about to share
Pre-1.0. Constrain to ^0.1.
composer install
composer test
composer phpstan
composer format| Package | What it owns |
|---|---|
laranail/validation |
The rules, the contracts, and the bundled fallbacks |
Questions and ideas in Discussions; bugs in Issues.
See CONTRIBUTING.md. Report vulnerabilities per SECURITY.md (opensource@simtabi.com); participation follows the Code of Conduct.
MIT © Simtabi LLC. See LICENSE.