feat(email): delivery you can see: each alert's email in history, outgoing email on Settings -> System (#5509)
#5509 "Delivery you can see: each alert's email state in history, and outgoing email on Settings -> System" (milestone 501). - Alerts -> History: an alert's email reads from the outbox (#5506): "gathering" with when it sends, "sending", "retrying" with the attempt, next try and the server's last answer, "sent", or "failed" naming each reader it didn't reach and why (outbox.delivery / email_states). Events from before the outbox keep what they recorded. The Notified column shows once an alert has a queued email. - Settings -> System gets "Outgoing email": every email of the last 7 days not yet sent, failures first, then the longest retrying, with recipient, kind, state and last error, and a count of what was sent. Failures and anything still retrying after 5 minutes lead the page's verdict (outbox.outgoing). - get_alert_history (MCP) adds `email`: the same delivery state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -223,3 +223,23 @@ def test_the_smtp_guard_can_fail():
|
||||
assert _smtp_openers({"x.py": " with smtplib.SMTP(host) as s:"}) == {"x.py"}
|
||||
assert _smtp_openers({"y.py": " smtp = notifications.smtp_open(cfg)"}) == {"y.py"}
|
||||
assert _smtp_openers({"z.py": "# smtp_open(cfg) is the outbox's\ndef smtp_open(cfg):"}) == set()
|
||||
|
||||
|
||||
# ── How an alert's email reads in history (#5509) ────────────────────────────
|
||||
|
||||
def test_an_alerts_email_reads_by_its_least_finished_copy():
|
||||
later, sent_at = NOW + timedelta(minutes=2), NOW + timedelta(seconds=5)
|
||||
held = _row(state="held", send_after=later, created_at=NOW)
|
||||
retrying = _row(recipient="b@x", state="pending", attempts=3, next_attempt_at=later,
|
||||
last_error="451 greylisted", created_at=NOW)
|
||||
sent = _row(recipient="c@x", state="sent", attempts=1, sent_at=sent_at, created_at=NOW)
|
||||
failed = _row(recipient="d@x", state="failed", attempts=1, first_attempt_at=NOW,
|
||||
last_error="550 no such user", created_at=NOW)
|
||||
first = _row(recipient="e@x", state="pending", attempts=0, next_attempt_at=NOW, created_at=NOW)
|
||||
assert outbox.delivery([sent, held, failed]) == {"state": "held", "at": later, "attempts": 0, "error": None}
|
||||
assert outbox.delivery([sent, retrying]) == {"state": "retrying", "at": later, "attempts": 3,
|
||||
"error": "451 greylisted"}
|
||||
assert outbox.delivery([first])["state"] == "sending"
|
||||
assert outbox.delivery([sent, failed]) == {"state": "failed", "at": NOW, "attempts": 1,
|
||||
"error": "d@x: 550 no such user"}
|
||||
assert outbox.delivery([sent]) == {"state": "sent", "at": sent_at, "attempts": 1, "error": None}
|
||||
|
||||
Reference in New Issue
Block a user