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
+56 -8
View File
@@ -813,15 +813,33 @@ async def imap_sync_folder(
and_( and_(
Mail.folder_id == folder_id, Mail.folder_id == folder_id,
Mail.tenant_id == tenant_id, Mail.tenant_id == tenant_id,
Mail.imap_uid.is_not(None),
) )
) )
) )
).scalars().all() ).scalars().all()
for db_mail in db_mails: 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:
logger.info("imap_sync_folder: deleting vanished mail %s (UID %s no longer on server)", db_mail.id, db_mail.imap_uid) if db_mail.imap_uid not in imap_uids_set:
await db.delete(db_mail) 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() await db.flush()
except Exception as vanished_exc: except Exception as vanished_exc:
logger.warning("imap_sync_folder: vanished-UID check failed for folder %s: %s", folder_id, 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_( and_(
Mail.folder_id == folder.id, Mail.folder_id == folder.id,
Mail.tenant_id == tenant_id, Mail.tenant_id == tenant_id,
Mail.imap_uid.is_not(None),
) )
) )
) )
).scalars().all() ).scalars().all()
for db_mail in db_mails: 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:
logger.info("imap_sync_account: deleting vanished mail %s (UID %s no longer on server)", db_mail.id, db_mail.imap_uid) if db_mail.imap_uid not in imap_uids_set:
await db.delete(db_mail) 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() await db.flush()
except Exception as vanished_exc: except Exception as vanished_exc:
logger.warning("imap_sync_account: vanished-UID check failed for folder %s: %s", folder.imap_name, 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': if append_resp.result == 'OK':
logger.info("send_mail: uploaded sent mail to IMAP folder %s", sent_folder.imap_name) 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: else:
logger.warning("send_mail: IMAP APPEND failed for sent folder %s: %s", sent_folder.imap_name, append_resp) logger.warning("send_mail: IMAP APPEND failed for sent folder %s: %s", sent_folder.imap_name, append_resp)
await imap_client.logout() await imap_client.logout()