fix: dedup by message_id in imap_sync_folder — stop deleted mails reappearing from Trash

- imap_sync_folder now checks message_id in addition to (folder_id, imap_uid)
- If mail was moved to Trash by IMAP server (new UID, same message_id), it is recognized
- Soft-deleted mails with matching message_id are skipped, not re-created
- Prevents deleted mails from reappearing when IMAP server moves them to Trash
This commit is contained in:
Agent Zero
2026-07-20 12:59:19 +02:00
parent 478ea877f9
commit 5ded6f7d0b
+31
View File
@@ -635,10 +635,41 @@ async def imap_sync_folder(
)
).scalar_one_or_none()
# Also check by message_id — mail may have been moved to Trash by IMAP server
if not existing_mail:
# Fetch headers first to get Message-ID
fetch_hdr = await client.uid('fetch', uid_str, '(BODY.PEEK[HEADER.FIELDS (MESSAGE-ID)])')
hdr_raw = None
for line in (fetch_hdr.lines if hasattr(fetch_hdr, 'lines') else fetch_hdr):
if isinstance(line, bytearray):
hdr_raw = bytes(line)
break
if hdr_raw:
hdr_msg = message_from_bytes(hdr_raw)
peek_msg_id = hdr_msg.get("Message-ID", "")
if peek_msg_id:
existing_mail = (
await db.execute(
select(Mail).where(
and_(
Mail.account_id == account.id,
Mail.message_id == peek_msg_id,
Mail.tenant_id == tenant_id,
)
)
)
).scalar_one_or_none()
if existing_mail:
# Don't touch soft-deleted mails — they're being deleted via sync queue
if existing_mail.deleted_at is not None:
continue
# Update folder_id and imap_uid if mail moved to a different folder
if existing_mail.folder_id != folder.id:
existing_mail.folder_id = folder.id
existing_mail.imap_uid = uid_str
elif not existing_mail.imap_uid:
existing_mail.imap_uid = uid_str
continue
# Fetch and parse the email