From 4cf4c4ad49d51da8d43b008a8cae262c3b7a7f21 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 13:02:19 +0000 Subject: [PATCH] fix: record alert key before send to prevent SMTP retry storm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit notifyWeatherAlerts() only inserted the alert key into sentAlertKeys_ when sendEmail() returned true. During an SMTP outage every tick re- attempted the same failed connection (one 30s block per active alert per tick), silently hammering the mail server with no backoff. Record the key unconditionally before the send attempt. If SMTP is down the alert is dropped for this activation window — best-effort loss of one email is acceptable; repeated connection attempts during an outage are not. Fixes #74 https://claude.ai/code/session_01WFdWug8ZDiJYr1ozfxwkn7 --- src/alerter.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/alerter.cpp b/src/alerter.cpp index d12df34..7bb4b65 100644 --- a/src/alerter.cpp +++ b/src/alerter.cpp @@ -155,19 +155,22 @@ void Alerter::notifyWeatherAlerts(const weather_alerts::AlertSet& alerts, if (!ready_) return; // 1. Send for new alerts we haven't seen before. + // The key is recorded before the send attempt so a transient SMTP + // failure does not cause the same alert to hammer the mail server + // once per tick for the duration of the outage. Best-effort delivery: + // a single missed email during an outage is acceptable. std::set currentKeys; for (const auto& a : alerts.active) { std::string key = weather_alerts::keyFor(a); currentKeys.insert(key); - if (sentAlertKeys_.count(key)) continue; // already emailed this one + if (sentAlertKeys_.count(key)) continue; std::ostringstream subj, body; subj << "[WeatherDisplay] " << a.headline; body << a.detail << "\n\n" << "Detected at: " << humanLocal(now) << "\n"; - if (sendEmail(subj.str(), body.str())) { - sentAlertKeys_.insert(key); - } + sentAlertKeys_.insert(key); + sendEmail(subj.str(), body.str()); } // 2. Forget keys for alerts that are no longer active, so if they