A queue that retries every 30 seconds looks diligent and behaves badly. Remote servers rate-limit per connection and per sender, so a tight retry loop turns one slow recipient into a block for every other recipient on that domain.
Classify before you retry
A 4xx response is temporary and may be retried. A 5xx response at RCPT or DATA is permanent for that recipient and must not be retried. The trap is 421 and 450: both are temporary, but they often mean 'you are sending too fast', so retrying the same message immediately makes it worse.
Back off per domain, not per message
The unit of pressure is the receiving domain. If example.org answers 421, every message queued for example.org should wait, not just the one that failed. Keep a per-domain state: last failure time, consecutive failures, and a next-allowed timestamp computed with exponential backoff and jitter. Two senders retrying in lockstep recreate the exact burst the remote server was complaining about, which is what the jitter is for.
Cap the total, not the interval
Most providers give a window: keep trying for 24 to 72 hours, then bounce. Without a cap, a permanently broken recipient stays in the queue forever and every metrics dashboard quietly lies about the size of the backlog.
One measurable detail
Log the remote response code and the text, not a boolean. When a customer asks why their email was late, '421 4.7.0 too many connections' explains it and 'retrying' does not.
Volanea exposes the per-domain retry state and the remote diagnostic on every send, so the queue behaviour is observable instead of assumed.
Top comments (0)