fix: IMAP sync - use imap_uid, add sync queue with retry, restore deleted on sync, upload sent mails
- imap_delete_mail: use stored imap_uid instead of Message-ID search, raise on failure - imap_move_mail: same imap_uid fix, raise on failure - New MailSyncQueue model + migration 0007 for pending IMAP operations - delete_mail route: queues failed IMAP delete for retry - move_mail route: queues failed IMAP move for retry - process_sync_queue: retries pending delete/move operations in auto-sync loop - Auto-sync loop: processes sync queue before pulling new mails - Restore soft-deleted mails if they still exist on IMAP server during sync - Upload sent mails to IMAP Sent folder via APPEND after SMTP send - Plugin version bumped to 1.2.0
This commit is contained in:
@@ -31,6 +31,7 @@ from app.plugins.builtins.mail.models import (
|
||||
MailLabelAssignment,
|
||||
MailRule,
|
||||
MailSignature,
|
||||
MailSyncQueue,
|
||||
MailTemplate,
|
||||
PgpKey,
|
||||
)
|
||||
@@ -1531,12 +1532,22 @@ async def delete_mail(
|
||||
# Soft-delete: set deleted_at = now()
|
||||
mail.deleted_at = datetime.now(UTC)
|
||||
await db.flush()
|
||||
# IMAP delete: non-critical, errors logged but DB soft-delete still succeeds
|
||||
# IMAP delete: queue for retry if it fails
|
||||
try:
|
||||
await mail_services.imap_delete_mail(db, m_id, tenant_id)
|
||||
except Exception as exc:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning("IMAP delete failed for mail %s: %s", m_id, exc)
|
||||
logging.getLogger(__name__).warning("IMAP delete failed for mail %s: %s, queuing for retry", m_id, exc)
|
||||
queue_entry = MailSyncQueue(
|
||||
tenant_id=tenant_id,
|
||||
mail_id=m_id,
|
||||
operation="delete",
|
||||
payload={},
|
||||
status="pending",
|
||||
last_error=str(exc),
|
||||
)
|
||||
db.add(queue_entry)
|
||||
await db.flush()
|
||||
|
||||
|
||||
@router.post("/{mail_id}/move")
|
||||
@@ -1570,12 +1581,22 @@ async def move_mail(
|
||||
# Update mail.folder_id
|
||||
mail.folder_id = target_f_id
|
||||
await db.flush()
|
||||
# IMAP move: non-critical
|
||||
# IMAP move: queue for retry if it fails
|
||||
try:
|
||||
await mail_services.imap_move_mail(db, m_id, target_f_id, tenant_id)
|
||||
except Exception as exc:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning("IMAP move failed for mail %s: %s", m_id, exc)
|
||||
logging.getLogger(__name__).warning("IMAP move failed for mail %s: %s, queuing for retry", m_id, exc)
|
||||
queue_entry = MailSyncQueue(
|
||||
tenant_id=tenant_id,
|
||||
mail_id=m_id,
|
||||
operation="move",
|
||||
payload={"target_folder_id": str(target_f_id)},
|
||||
status="pending",
|
||||
last_error=str(exc),
|
||||
)
|
||||
db.add(queue_entry)
|
||||
await db.flush()
|
||||
return mail_to_response(mail)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user