fix(mail): save attachments for existing emails during sync
- IMAP sync now saves attachments for existing emails that have has_attachments=true but no attachment records in the database (retroactive attachment saving) - Replace silent exception catching with logger.warning for attachment save failures - Add logging module import and logger instance - This fixes the issue where 62 emails had has_attachments=true but 0 attachment records
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -39,6 +40,8 @@ from app.plugins.builtins.mail.models import (
|
|||||||
VacationSentLog,
|
VacationSentLog,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# ─── Attachment Storage Helpers ───
|
# ─── Attachment Storage Helpers ───
|
||||||
|
|
||||||
MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024 # 25 MB
|
MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024 # 25 MB
|
||||||
@@ -754,6 +757,38 @@ async def imap_sync_account(
|
|||||||
)
|
)
|
||||||
).scalar_one_or_none()
|
).scalar_one_or_none()
|
||||||
if existing_mail:
|
if existing_mail:
|
||||||
|
# Save attachments for existing emails that have has_attachments but no records
|
||||||
|
if attachments and existing_mail.has_attachments:
|
||||||
|
existing_att_count = (
|
||||||
|
await db.execute(
|
||||||
|
select(text("COUNT(*)")).where(
|
||||||
|
and_(
|
||||||
|
MailAttachment.mail_id == existing_mail.id,
|
||||||
|
MailAttachment.tenant_id == tenant_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).scalar() or 0
|
||||||
|
if existing_att_count == 0:
|
||||||
|
for att_data in attachments:
|
||||||
|
try:
|
||||||
|
storage_path = await _save_attachment_to_storage(
|
||||||
|
existing_mail.id, att_data["filename"], att_data["content"]
|
||||||
|
)
|
||||||
|
attachment = MailAttachment(
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
mail_id=existing_mail.id,
|
||||||
|
filename=_sanitize_filename(att_data["filename"]),
|
||||||
|
mime_type=att_data["mime_type"],
|
||||||
|
size_bytes=att_data["size"],
|
||||||
|
storage_path=storage_path,
|
||||||
|
content_id=att_data.get("content_id"),
|
||||||
|
)
|
||||||
|
db.add(attachment)
|
||||||
|
except Exception as att_err:
|
||||||
|
logger.warning(f"Failed to save attachment for existing mail {existing_mail.id}: {att_err}")
|
||||||
|
continue
|
||||||
|
await db.flush()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mail = Mail(
|
mail = Mail(
|
||||||
@@ -801,8 +836,8 @@ async def imap_sync_account(
|
|||||||
content_id=att_data.get("content_id"),
|
content_id=att_data.get("content_id"),
|
||||||
)
|
)
|
||||||
db.add(attachment)
|
db.add(attachment)
|
||||||
except Exception:
|
except Exception as att_err:
|
||||||
# Skip attachments that fail to save
|
logger.warning(f"Failed to save attachment for new mail {mail.id}: {att_err}")
|
||||||
continue
|
continue
|
||||||
await db.flush()
|
await db.flush()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user