From 4019283eba72bde4dbacf8086533b5fd0a8b65a8 Mon Sep 17 00:00:00 2001 From: Paulo Victor Cordeiro <146781332+pvcordeiro@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:35:36 +0100 Subject: [PATCH] fix: IMAP connection leak in _imap_move on store/expunge failure (#1325) If c.store() or c.expunge() raised an exception, the connection was never logged out. Use try/finally to ensure c.logout() is always called regardless of how the function exits. --- routes/email_helpers.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/routes/email_helpers.py b/routes/email_helpers.py index 226c9a7..180ebf9 100644 --- a/routes/email_helpers.py +++ b/routes/email_helpers.py @@ -847,20 +847,25 @@ def _detect_spam_folder(conn): def _imap_move(uid, dest, src="INBOX", account_id: str | None = None, owner: str = ""): """Move a single IMAP UID from src folder to dest. Returns True on success.""" + c = None try: c = _imap_connect(account_id, owner=owner) c.select(_q(src)) status, _ = c.copy(uid, _q(dest)) if status != "OK": - c.logout() return False c.store(uid, "+FLAGS", "\\Deleted") c.expunge() - c.logout() return True except Exception as e: logger.warning(f"IMAP move {uid} → {dest} failed: {e}") return False + finally: + if c: + try: + c.logout() + except Exception: + pass def _extract_attachment_text(msg, max_chars: int = 6000) -> str: