The daemon fetched requests-tier mail and then never looked at that folder, so
an unknown sender's mail sat in the local store unseen and undeleted. poll now
reads both tiers and deletes from both; delete_local removes by id from the
inbox table whatever the tier, so nothing can loop.
Dropped the `summary.stored == 0` early return. It meant a row left behind by
an error path on one cycle was only revisited if something new arrived later.
Emptiness is now decided from the rows actually in hand.
A live mail.db holds every requests-tier mail it ever received, so the first
poll of a version that reads them would answer every stranger in that history
at once. drain_backlog discards that backlog once and records it in state.
Not a received_at watermark: that timestamp is the server's, and clock skew
would silently discard real mail. It drains only the requests rows, so inbox
mail in the same cycle is still processed.
send_replies no longer aborts the batch on the first failure. It returned Err
on one unreachable recipient, dropping every later reply — tolerable when
replies only went to admitted authors, not once they go to arbitrary servers
and an author's accept token can be queued behind a host that is down. It now
counts failures and reports them in the poll summary.
The per-poll network cap is deliberately not here: the dials it bounds live in
the handlers, so it lands with them.