RcmEmailAutomation / app /lib /graph /email_processor.py
cmoss3's picture
Error handling, confidence scoring, daily brief, deduplicate webhook notifications
0a367ef
Raw
History Blame Contribute Delete
1.97 kB
import base64
import logging
from pathlib import Path
import aiosqlite
from app.config import settings
from app.database import update_notification_status
from app.lib.graph.client import GraphClient
from app.lib.utils.storage import write_email
logger = logging.getLogger(__name__)
_LARGE_ATTACHMENT_THRESHOLD = 3 * 1024 * 1024 # 3 MB
async def fetch_and_store(
client: GraphClient,
message_id: str,
notif_db_id: int,
storage_path: Path,
conn: aiosqlite.Connection,
) -> Path:
email_data = await client.get(
f"/users/{settings.mailbox_user}/messages/{message_id}",
params={"$expand": "attachments", "$select": (
"id,subject,from,toRecipients,ccRecipients,receivedDateTime,"
"body,uniqueBody,hasAttachments,attachments,webLink"
)},
)
attachment_bytes: list[tuple[str, str, bytes]] = []
for att in email_data.get("attachments", []):
if att.get("@odata.type") != "#microsoft.graph.fileAttachment":
continue
filename = att.get("name", "attachment")
content_type = att.get("contentType", "application/octet-stream")
size = att.get("size", 0)
if size > _LARGE_ATTACHMENT_THRESHOLD or not att.get("contentBytes"):
raw = await _fetch_large_attachment(client, message_id, att["id"])
else:
raw = base64.b64decode(att["contentBytes"])
attachment_bytes.append((filename, content_type, raw))
dest = await write_email(email_data, attachment_bytes, storage_path)
await update_notification_status(
conn, notif_db_id, "fetched", storage_path=str(dest)
)
logger.info("Stored email %s at %s", message_id, dest)
return dest
async def _fetch_large_attachment(
client: GraphClient, message_id: str, attachment_id: str
) -> bytes:
return await client.get_raw(
f"/users/{settings.mailbox_user}/messages/{message_id}/attachments/{attachment_id}/$value"
)