diff --git a/app/plugins/builtins/mail/services.py b/app/plugins/builtins/mail/services.py index 06ae2ac..3a9098c 100644 --- a/app/plugins/builtins/mail/services.py +++ b/app/plugins/builtins/mail/services.py @@ -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