fix: retrieve UID after IMAP APPEND + handle uid=None mails in vanished check

This commit is contained in:
Agent Zero
2026-07-20 16:48:41 +02:00
parent a2d68e1aca
commit e1a9a8e33e
+52 -4
View File
@@ -813,15 +813,33 @@ async def imap_sync_folder(
and_(
Mail.folder_id == folder_id,
Mail.tenant_id == tenant_id,
Mail.imap_uid.is_not(None),
)
)
)
).scalars().all()
for db_mail in db_mails:
if db_mail.imap_uid and db_mail.imap_uid not in imap_uids_set:
if db_mail.imap_uid:
if db_mail.imap_uid not in imap_uids_set:
logger.info("imap_sync_folder: deleting vanished mail %s (UID %s no longer on server)", db_mail.id, db_mail.imap_uid)
await db.delete(db_mail)
elif db_mail.message_id:
# Mail has no UID — try to find it on IMAP by Message-ID
try:
mid_search = await client.uid_search(f'HEADER Message-ID "{db_mail.message_id}"')
mid_raw = mid_search[1][0] if mid_search[1] and mid_search[1][0] else b''
if isinstance(mid_raw, (bytes, bytearray)) and mid_raw:
found_uids = mid_raw.decode().split()
if found_uids:
db_mail.imap_uid = found_uids[0]
logger.info("imap_sync_folder: found UID %s for mail %s via Message-ID", found_uids[0], db_mail.id)
else:
logger.info("imap_sync_folder: deleting mail %s (no UID, not found on server by Message-ID)", db_mail.id)
await db.delete(db_mail)
else:
logger.info("imap_sync_folder: deleting mail %s (no UID, not found on server by Message-ID)", db_mail.id)
await db.delete(db_mail)
except Exception as mid_exc:
logger.warning("imap_sync_folder: Message-ID search failed for mail %s: %s", db_mail.id, mid_exc)
await db.flush()
except Exception as vanished_exc:
logger.warning("imap_sync_folder: vanished-UID check failed for folder %s: %s", folder_id, vanished_exc)
@@ -1296,15 +1314,33 @@ async def imap_sync_account(
and_(
Mail.folder_id == folder.id,
Mail.tenant_id == tenant_id,
Mail.imap_uid.is_not(None),
)
)
)
).scalars().all()
for db_mail in db_mails:
if db_mail.imap_uid and db_mail.imap_uid not in imap_uids_set:
if db_mail.imap_uid:
if db_mail.imap_uid not in imap_uids_set:
logger.info("imap_sync_account: deleting vanished mail %s (UID %s no longer on server)", db_mail.id, db_mail.imap_uid)
await db.delete(db_mail)
elif db_mail.message_id:
# Mail has no UID — try to find it on IMAP by Message-ID
try:
mid_search = await client.uid_search(f'HEADER Message-ID "{db_mail.message_id}"')
mid_raw = mid_search[1][0] if mid_search[1] and mid_search[1][0] else b''
if isinstance(mid_raw, (bytes, bytearray)) and mid_raw:
found_uids = mid_raw.decode().split()
if found_uids:
db_mail.imap_uid = found_uids[0]
logger.info("imap_sync_account: found UID %s for mail %s via Message-ID", found_uids[0], db_mail.id)
else:
logger.info("imap_sync_account: deleting mail %s (no UID, not found on server by Message-ID)", db_mail.id)
await db.delete(db_mail)
else:
logger.info("imap_sync_account: deleting mail %s (no UID, not found on server by Message-ID)", db_mail.id)
await db.delete(db_mail)
except Exception as mid_exc:
logger.warning("imap_sync_account: Message-ID search failed for mail %s: %s", db_mail.id, mid_exc)
await db.flush()
except Exception as vanished_exc:
logger.warning("imap_sync_account: vanished-UID check failed for folder %s: %s", folder.imap_name, vanished_exc)
@@ -1559,6 +1595,18 @@ async def send_mail_via_smtp(
)
if append_resp.result == 'OK':
logger.info("send_mail: uploaded sent mail to IMAP folder %s", sent_folder.imap_name)
# Retrieve the new UID for the appended mail by searching for its Message-ID
try:
await imap_client.select(sent_folder.imap_name)
search_resp = await imap_client.uid_search(f'HEADER Message-ID "{msg_id}"')
uid_raw = search_resp[1][0] if search_resp[1] and search_resp[1][0] else b''
if isinstance(uid_raw, (bytes, bytearray)) and uid_raw:
new_uids = uid_raw.decode().split()
if new_uids:
sent_mail.imap_uid = new_uids[0]
logger.info("send_mail: set imap_uid=%s for sent mail %s", new_uids[0], sent_mail.id)
except Exception as uid_exc:
logger.warning("send_mail: could not retrieve UID after APPEND: %s", uid_exc)
else:
logger.warning("send_mail: IMAP APPEND failed for sent folder %s: %s", sent_folder.imap_name, append_resp)
await imap_client.logout()