handoff fixes
This commit is contained in:
parent
6c52cd19cb
commit
89ddebdb60
15 changed files with 991 additions and 271 deletions
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue