Problem
The cheap answer and the expensive answer look the same
Sending to a dirty list is expensive in a way that compounds: bounces damage sender reputation, reputation damage suppresses delivery of the mail that would have converted, and by the time the metrics show it the damage is weeks old. So lists have to be cleaned before a send, not after.
The naive implementation runs a full network verification against every address on the list. It works, and it is unusable at scale — slow, rate-limited by the receiving side, and paying full price for addresses that a regular expression could have rejected in a microsecond. The verdict is identical; the cost differs by orders of magnitude.
Architecture
A cascade, ordered strictly by what each check costs
The system is a tiered pipeline where each address falls through only as far as it has to. Syntax and structural validation first — free, local, instant. Domain-level checks next: does the domain exist, does it publish mail exchange records, is it a known disposable or throwaway provider. Only what survives all of that reaches the network tier, where an actual conversation with the receiving server is attempted.
Classification runs alongside the validity question: role addresses, catch-all domains and disposables are flagged as categories rather than collapsed into valid or invalid, because a role address is deliverable and still usually a bad idea to mail.
The architecture is one rule applied repeatedly: never spend a network round trip on a question that a local check already answered.
Bulk work runs as queued jobs with per-domain pacing, because hitting one provider hard is the fastest way to get every subsequent check refused. Results are cached by domain where the answer is a domain-level property, so a list with ten thousand addresses at the same provider asks the expensive question once.
AI components
Pattern learning where the rules run out
- Pattern classification — disposable and throwaway providers appear faster than any static list can be maintained. Structural and behavioural patterns generalise where an enumerated blocklist cannot.
- Catch-all and behaviour inference — some domains accept everything, which makes a positive network result meaningless. Detecting that is a property of how a server behaves across probes, not of any single response.
- Risk scoring rather than binary output — addresses that survive every check but carry risk signals are returned as risky, so the user decides their own tolerance instead of inheriting mine.
- Deliberately not AI — syntax, mail exchange records and the network conversation itself. These have exact answers and a model would only add cost and doubt to a question already fully decided.
What it runs today
Lists go in, verdicts come out, at bulk
The system runs list ingestion, deduplication, tiered verification, categorisation and export as a queued pipeline, so a large list is processed as a job with progress rather than as a request that times out.
The behaviour we care most about is what happens when it cannot tell. An address that reaches the network tier and gets an ambiguous response is returned as unknown, not rounded to valid. Unknown is a real verdict with a real meaning, and collapsing it into a guess is how verification tools quietly destroy the reputation they were bought to protect.
Outcome
Cost per verified address, not accuracy theatre
The metric that matters in this system is not an accuracy percentage — it is how much it costs to reach a confident verdict on the average address. The cascade means most addresses are decided before any network cost is incurred at all, and the expensive tier operates on a small residual slice.
That is the same discipline we apply to model spend on every other platform on this site: Arthastra routes classification through deterministic rules and learned patterns before a model is ever called, for exactly the reason MailTidy checks syntax before it opens a socket. Tiering by cost is not an optimisation you add later. It is the shape of the system.