Issue Description
A task-generated report message (DMARC/TLS-RPT) sitting in the default
queue never gets its first delivery retry attempted, even long after its
scheduled nextRetry time has passed.
Stalwart version: v0.16.19 (Docker image, digest-pinned)
Platform: rootless Podman on a Debian-based VPS
Expected Behavior
Once a queued message’s nextRetry time is reached, the queue scheduler
attempts delivery on its next pass and increments Retry Count — whether
that attempt succeeds or fails.
Actual Behavior
A TLS-RPT report (returnPath noreply-tls@, recipient
[email protected], queue: default, flagged “Message is an automated
report (DMARC, TLS-RPT, etc.)”) had its nextRetry time pass and then
stayed overdue by more than an hour, with Retry Count remaining 0 the
entire time — not one delivery attempt was made, successful or failed.
Manually forcing the field via stalwart-cli update QueuedMessage <id> --field nextRetry=<now> triggered immediate, successful delivery on the
very next pass. So the delivery mechanism itself works fine once
triggered — something upstream of it (the wakeup/scheduling signal)
Reproduction Steps
I don’t have a minimal reproduction sequence — this was noticed live, not
deliberately triggered. Observed sequence, not a confirmed trigger:
- Server running normally, handling regular SMTP traffic.
- An internal task generates a TLS-RPT aggregate report for delivery.
- Its nextRetry time passes at some point before I noticed.
- Found over an hour overdue with Retry Count still 0.
Unknown what specifically would make this reproducible on demand. Will
follow up with a tighter sequence if it recurs.
Relevant Log Output
Not available. The Tracer was running at info level at the time of the
incident, and the affected message is gone now (delivered after the
manual nextRetry fix), so I can’t retroactively extract trace output for
this specific occurrence. Happy to raise the Tracer to trace and follow
up with logs if/when this recurs.
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
One possibly related prior report, same subsystem (queue scheduler
timing), already fixed:
Mails queue cannot be changed —
next_delivery_event() only considered retry.due while the queue index
uses min(retry.due, notify.due, expires), fixed in v0.16.9. I’m on
v0.16.19 so this specific fix should be present; the failure mode looks
like the same family of bug, possibly an edge case the fix didn’t cover.
There’s also a thread titled “BlockedIp/AllowedIp changes via settings
API don’t take effect until restart” (couldn’t link it, 2-link limit for
new users) confirming a broader pattern in the codebase: in-memory state
populated at startup that some write paths don’t trigger a reload/notify
for.
My unverified guess (haven’t checked the source): report messages, which go through a
separate staging queue before a background task assembles and inserts
them into the main queue, take an insertion path that doesn’t trigger
whatever wakeup signal the live queue scheduler needs — unlike a normal
SMTP-submitted message or an explicit API update.
Impact: only Stalwart’s own generated reports seem affected so far, not
normal SMTP-submitted mail — but I haven’t confirmed that boundary, just
haven’t seen it happen to user mail.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on