mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-07 10:33:24 -08:00
[SMTP] Add reliable email delivery with retry and database-backed queue (#7240)
* [SMTP] Add reliable email delivery with retry and database-backed queue Rework the SMTP client from fire-and-forget sending into a persistent queue with exponential backoff and per-message retry budget, backed by the existing database rows as the durable source of truth. - Keep pending emails in an in-memory queue with attempts/backoff tracking; enqueue without deleting database rows, and only remove the row once delivery is confirmed via the mailDelivered signal. - Add exponential backoff (doubling, capped at 30 min) between delivery attempts, bounded by new smtp/maxretries and smtp/retrydelay settings. - Track connection-layer failures (connect/auth/encrypt) with their own backoff; route failures to recordFailed/recordConnectionFailure so undeliverable mail eventually drops from the queue instead of retrying forever. - Treat rejected recipients/senders as permanent failures. - Rebuild the SMTP buffer from the authoritative queue before each send via a new QxtSmtp::reset() so reconnects never duplicate deliveries. - Start the idle timeout after authentication, not on TCP connect, so slow SSL/STARTTLS handshakes are not cut short. * [SMTP] Fix retry accounting, backoff reset, and token dedupe --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
1a4d89ff8f
commit
8968709642
7 changed files with 655 additions and 133 deletions
|
|
@ -94,6 +94,38 @@ int QxtSmtp::pendingMessages() const
|
|||
return qxt_d().pending.count();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Drops all queued (not yet transmitted) messages without sending them.
|
||||
*
|
||||
* Any message still awaiting delivery is discarded. This is used by callers that
|
||||
* keep their own authoritative queue and wish to rebuild the SMTP buffer from scratch
|
||||
* (e.g. after a reconnect) without risking duplicates.
|
||||
*/
|
||||
void QxtSmtp::clearPending()
|
||||
{
|
||||
qxt_d().pending.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the outgoing queue and resets the SMTP state machine.
|
||||
*
|
||||
* Unlike clearPending(), this also resets the internal state to Disconnected so
|
||||
* that subsequent send() calls will not fire sendNext() prematurely on a
|
||||
* not-yet-connected socket. Use this when rebuilding the queue from scratch
|
||||
* before a fresh connectToHost() / connectToSecureHost() cycle.
|
||||
*/
|
||||
void QxtSmtp::reset()
|
||||
{
|
||||
qxt_d().pending.clear();
|
||||
qxt_d().extensions.clear();
|
||||
qxt_d().buffer.clear();
|
||||
qxt_d().recipients.clear();
|
||||
qxt_d().rcptNumber = 0;
|
||||
qxt_d().rcptAck = 0;
|
||||
qxt_d().mailAck = false;
|
||||
qxt_d().state = QxtSmtpPrivate::Disconnected;
|
||||
}
|
||||
|
||||
QTcpSocket *QxtSmtp::socket() const
|
||||
{
|
||||
return qxt_d().socket;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue