Classify before retrying

Capture the stage that failed: DNS resolution, TCP connection, TLS negotiation, SMTP greeting, MailFrom, or RcptTo. Record remote host, response code and enhanced code when present, elapsed time, attempt, and UTC timestamp. Redact local parts from ordinary logs.

A 4yz SMTP reply indicates a temporary negative response and normally invites retry. A network timeout provides less information: the server may be slow, filtering the source, overloaded, or unreachable. Neither proves that the mailbox is invalid.

Greylisting often remembers a tuple such as source IP, envelope sender, and recipient. Retrying from a different egress address or constantly changing the envelope can look like a new attempt and remain greylisted.

Use a bounded queue

Move network checks out of the web request. Set connection, command, and total deadlines; cap DNS answers, MX hosts, attempts, concurrency, and per-domain work. Use exponential or documented backoff with jitter rather than immediate loops. Preserve the same logical test identity where the authorized design and greylisting behavior require it.

Stop on a clear permanent response, successful evidence, expiration, user cancellation, or quota. Do not cycle through every MX indefinitely. Apply domain-wide circuit breaking when a provider is failing so one outage does not amplify traffic.

Return useful states

Model valid, invalid, accept-all/ambiguous, temporary, unavailable, and unknown separately. Include retry_after only when your own scheduler can honor it; do not expose internal hosts or provider text that contains addresses.

If a provider rate-limits or blocks verification, respect it. Do not rotate IPs to evade controls. Maintain reverse DNS, abuse contact, and source identification for authorized egress.

Verify the retry policy

Use a local fixture server to simulate greeting delays, 421, 450, timeout, successful retry, and permanent 550 responses. Assert bounded wall time and exact state transitions. In live operation, compare retry success rate, latency, and provider complaints.

An honest final result may be “unknown after two bounded temporary attempts.” That protects a potentially valid address from false rejection and protects remote infrastructure from unbounded verification traffic.