Why five gates?
A single regex check tells you nothing. An email can pass syntax validation, resolve MX records, and still bounce — because the mailbox doesn't exist, the domain is a catch-all, or the address is a department alias that never reads cold outreach. Each gate eliminates a different class of false positives.
The SMTP handshake
The optional fifth gate connects to the best MX host on port 25 with a 10-second timeout. The dialogue: read the banner (220), say HELO, issue MAIL FROM, then RCPT TO — the actual deliverability signal. The server responds 250 (accepted) or 5xx (rejected). We never send message content — just the envelope. A 4xx response means greylisting, which we mark as inconclusive rather than false-negative.
The receipt ledger
Every check writes a typed receipt to an append-only JSONL file. The key is (kind, value) — so a PASS on email_smtp can never mask a FAIL on email_domain_mx. When save_contacts runs, it consults the ledger: SMTP accepted? → Verified. Syntax+MX ok? → Partial. Otherwise → Unverified. This keeps status labels tied to recorded evidence rather than an unreviewed claim.
Auto-save: the safety net
The LLM doesn't always remember to call save_contacts. So after every extract_contacts or find_leads call, the runtime automatically persists harvested contacts — with the same dedup and receipt-gated verification. Structured records can reach the database even when the model skips a save call or context is compacted, subject to the runtime's configured persistence path.