handoff fixes

This commit is contained in:
debu-2 2026-10-06 02:44:54 +05:30
parent 6c52cd19cb
commit 89ddebdb60
15 changed files with 991 additions and 271 deletions

View file

@ -17,6 +17,7 @@ from app.services.human_handoff_service import (
resolve_handoff_from_inbound,
maybe_trigger_handoff,
)
from app.services.message_ids import normalize_message_id
from app.services.mime_parser import parse_mime
from app.services.raw_mime_storage import delivery_digest, get_raw_mime_storage
from app.services.thread_resolver import participants_from_parsed, resolve_thread
@ -38,6 +39,38 @@ def peer_is_allowed(session) -> bool:
return False
def log_smtp_message_received(
*,
message_id: str | None,
in_reply_to: str | None,
references: list[str],
sender: str,
recipient: str,
subject: str,
resolved_scope: str,
resolved_thread_id,
resolution_method: str,
stored_message_id,
mailbox_id: str = "inbox",
) -> None:
logger.info(
"smtp_message_received message_id=%s in_reply_to=%s references=%s "
"from=%s to=%s subject=%s resolved_scope=%s resolved_thread_id=%s "
"resolution_method=%s stored_message_id=%s mailbox_id=%s",
message_id,
in_reply_to,
" ".join(references or []),
sender,
recipient,
subject,
resolved_scope,
resolved_thread_id,
resolution_method,
stored_message_id,
mailbox_id,
)
class InboundHandler:
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
if not peer_is_allowed(session):
@ -55,6 +88,12 @@ class InboundHandler:
if not hasattr(envelope, "account_ids"):
envelope.account_ids = {}
envelope.account_ids[normalized] = str(account.id)
logger.info(
"smtp_rcpt_accepted mail_from=%s rcpt_to=%s account_id=%s",
envelope.mail_from.lower(),
normalized,
envelope.account_ids[normalized],
)
return "250 2.1.5 Recipient OK"
async def handle_DATA(self, server, session, envelope):
@ -74,12 +113,22 @@ class InboundHandler:
{"_id": 1},
):
return f"250 2.0.0 Message previously accepted as {delivery_key}"
logger.info(
"smtp_data_accepted mail_from=%s rcpt_to=%s delivery_key=%s bytes=%s",
envelope.mail_from.lower(),
",".join(recipients),
delivery_key,
len(raw),
)
parsed = parse_mime(raw)
body_text = parsed.pop("body_text")
body_html = parsed.pop("body_html")
stored = await get_raw_mime_storage().put(raw, delivery_key)
now = datetime.now(timezone.utc)
sender_address = (parsed.get("sender") or {}).get("address", "").lower()
internet_message_id = normalize_message_id(parsed.get("message_id"))
for recipient in recipients:
account_id = envelope.account_ids[recipient]
@ -111,6 +160,8 @@ class InboundHandler:
"delivery_key": delivery_key,
"received_at": now,
"created_at": now,
"message_id": internet_message_id,
"internet_message_id": internet_message_id,
}
await process_human_reply(
mongo_db,
@ -121,10 +172,18 @@ class InboundHandler:
inbound_body=body_text,
domain=domain,
)
logger.info(
"handoff_human_reply handoff_id=%s account=%s",
handoff["_id"],
account_id,
log_smtp_message_received(
message_id=internet_message_id,
in_reply_to=parsed.get("in_reply_to"),
references=parsed.get("references", []),
sender=sender_address,
recipient=recipient,
subject=parsed.get("subject", ""),
resolved_scope=MESSAGE_SCOPE_HANDOFF,
resolved_thread_id=handoff.get("handoff_thread_id"),
resolution_method="handoff_in_reply_to",
stored_message_id=None,
mailbox_id="handoff",
)
return f"250 2.0.0 Handoff reply accepted as {delivery_key}"
@ -135,6 +194,8 @@ class InboundHandler:
"envelope_sender": envelope.mail_from.lower(),
"envelope_recipients": recipients,
"delivery_key": delivery_key,
"message_id": internet_message_id,
"internet_message_id": internet_message_id,
"raw_mime": {
"bucket": stored.bucket,
"name": stored.name,
@ -156,7 +217,7 @@ class InboundHandler:
if persisted is None:
raise RuntimeError("Inbound message was not persisted.")
if body_text:
if body_text or body_html:
await mongo_db.messages.update_one(
{"_id": persisted["_id"]},
{"$set": {"body_text": body_text, "body_html": body_html}},
@ -191,7 +252,9 @@ class InboundHandler:
{
"$set": {
"message_scope": MESSAGE_SCOPE_EXTERNAL,
"in_reply_to": parsed.get("in_reply_to"),
"message_id": internet_message_id,
"internet_message_id": internet_message_id,
"in_reply_to": normalize_message_id(parsed.get("in_reply_to")),
"references": parsed.get("references", []),
"raw_headers": parsed.get("raw_headers", {}),
"parent_message_id": resolution.parent_message_id,
@ -200,7 +263,7 @@ class InboundHandler:
}
},
)
await mongo_db.mailbox_entries.update_one(
mailbox_result = await mongo_db.mailbox_entries.update_one(
{
"account_id": account_id,
"message_id": persisted["_id"],
@ -244,10 +307,26 @@ class InboundHandler:
external_thread_id=thread_id,
domain=domain,
)
log_smtp_message_received(
message_id=internet_message_id,
in_reply_to=parsed.get("in_reply_to"),
references=parsed.get("references", []),
sender=sender_address,
recipient=recipient,
subject=parsed.get("subject", ""),
resolved_scope=MESSAGE_SCOPE_EXTERNAL,
resolved_thread_id=thread_id,
resolution_method=resolution.thread_resolution_method,
stored_message_id=persisted["_id"],
mailbox_id="inbox",
)
logger.info(
"message_received message_id=%s thread_id=%s scope=EXTERNAL",
"message_received message_id=%s internet_message_id=%s thread_id=%s "
"scope=EXTERNAL mailbox_entry_upserted=%s",
persisted["_id"],
internet_message_id,
thread_id,
mailbox_result.upserted_id is not None or mailbox_result.modified_count > 0,
)
except Exception:
logger.exception("Temporary failure accepting inbound message")