from __future__ import annotations from dataclasses import dataclass from datetime import datetime from uuid import uuid5, NAMESPACE_URL from .models import ( AssessmentCategory, Confidence, EmailEvidenceCandidate, EndpointQualityUpdate, EvidenceStrength, MessageClass, ParsedMailboxMessage, ) @dataclass(frozen=True) class EvidenceMapping: event_type: str assessment_category: AssessmentCategory assessment_subclass: str evidence_strength: EvidenceStrength normalized_meaning: str EVIDENCE_MAPPINGS: dict[MessageClass, EvidenceMapping | None] = { MessageClass.HARD_BOUNCE: EvidenceMapping( "notification.endpoint.rejected_permanent", AssessmentCategory.FAIL, "fail.hard_bounce", EvidenceStrength.NEGATIVE, "Strong evidence that the recipient endpoint rejected the message permanently.", ), MessageClass.SOFT_BOUNCE: EvidenceMapping( "notification.endpoint.rejected_temporary", AssessmentCategory.UNDEF, "undef.deferred", EvidenceStrength.AMBIGUOUS, "Temporary endpoint failure; retry or later evidence may change interpretation.", ), MessageClass.DELAYED_DELIVERY_NOTICE: EvidenceMapping( "notification.endpoint.deferred", AssessmentCategory.UNDEF, "undef.deferred", EvidenceStrength.AMBIGUOUS, "Delivery is delayed and still uncertain.", ), MessageClass.FINAL_DELIVERY_FAILURE: EvidenceMapping( "notification.endpoint.rejected_permanent", AssessmentCategory.FAIL, "fail.expired_without_delivery", EvidenceStrength.NEGATIVE, "Provider or endpoint gave up after retrying.", ), MessageClass.OUT_OF_OFFICE: EvidenceMapping( "interaction.out_of_office_received", AssessmentCategory.UNDEF, "undef.out_of_office", EvidenceStrength.WEAK, "Mailbox auto-reply was observed; awareness and action remain uncertain.", ), MessageClass.HUMAN_REPLY: EvidenceMapping( "interaction.reply_received", AssessmentCategory.SUCCESS, "success.reply_received", EvidenceStrength.MEDIUM, "A reply-like message was observed on the email channel.", ), MessageClass.COMPLAINT_OR_ABUSE: EvidenceMapping( "notification.channel.complaint_received", AssessmentCategory.FAIL, "fail.complaint_received", EvidenceStrength.NEGATIVE, "Complaint or abuse feedback was observed.", ), MessageClass.UNSUBSCRIBE_OR_OPT_OUT: EvidenceMapping( "notification.channel.unsubscribe_received", AssessmentCategory.FAIL, "fail.unsubscribed", EvidenceStrength.NEGATIVE, "Opt-out or unsubscribe signal was observed.", ), MessageClass.UNKNOWN_RETURN_MESSAGE: EvidenceMapping( "notification.endpoint.unknown", AssessmentCategory.UNDEF, "undef.conflicting_evidence", EvidenceStrength.AMBIGUOUS, "Return-channel message could not be classified reliably.", ), MessageClass.CHALLENGE_RESPONSE: EvidenceMapping( "interaction.unverified_actor_interaction", AssessmentCategory.UNDEF, "undef.identity_uncertain", EvidenceStrength.AMBIGUOUS, "Challenge-response or automated interaction was observed.", ), MessageClass.UNRELATED_MESSAGE: None, MessageClass.PARSE_FAILED: EvidenceMapping( "diagnostic.message.parse_failed", AssessmentCategory.UNDEF, "undef.parse_failed", EvidenceStrength.NONE, "Message source could not be parsed reliably; no delivery or interaction claim is made.", ), } def evidence_deduplication_key(parsed: ParsedMailboxMessage, mapping: EvidenceMapping) -> str: parts = [ parsed.mailbox_message_id, parsed.parser_version, mapping.event_type, parsed.affected_email_address or "", parsed.original_message_id or "", parsed.smtp_status_code or "", parsed.enhanced_status_code or "", parsed.reason_code or "", ] return "|".join(parts) def candidate_from_parsed( parsed: ParsedMailboxMessage, *, raw_message_ref: str | None, observed_at: datetime, occurred_at: datetime | None, ) -> EmailEvidenceCandidate | None: mapping = EVIDENCE_MAPPINGS.get(parsed.message_class) if mapping is None: return None dedup_key = evidence_deduplication_key(parsed, mapping) candidate_id = str(uuid5(NAMESPACE_URL, "email-connect:evidence:" + dedup_key)) return EmailEvidenceCandidate( evidence_candidate_id=candidate_id, mailbox_message_id=parsed.mailbox_message_id, parsed_message_id=parsed.parsed_message_id, event_type=mapping.event_type, assessment_category=mapping.assessment_category, assessment_subclass=mapping.assessment_subclass, affected_email_address=parsed.affected_email_address, original_message_id=parsed.original_message_id, confidence=parsed.confidence, evidence_strength=mapping.evidence_strength, occurred_at=occurred_at, observed_at=observed_at, deduplication_key=dedup_key, raw_message_ref=raw_message_ref, notes=[mapping.normalized_meaning, *parsed.notes], metadata={ "message_class": parsed.message_class.value, "smtp_status_code": parsed.smtp_status_code, "enhanced_status_code": parsed.enhanced_status_code, "reason_code": parsed.reason_code, }, ) def endpoint_quality_from_candidate(candidate: EmailEvidenceCandidate) -> EndpointQualityUpdate | None: address = candidate.affected_email_address if not address: return None message_class = candidate.metadata.get("message_class") signal = str(message_class or candidate.event_type) reason_code = candidate.metadata.get("reason_code") observed_at = candidate.observed_at if message_class in {MessageClass.HARD_BOUNCE.value, MessageClass.FINAL_DELIVERY_FAILURE.value}: return EndpointQualityUpdate( affected_email_address=address.lower(), reachability="unreachable", last_failure_at=observed_at, reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) if message_class in {MessageClass.SOFT_BOUNCE.value, MessageClass.DELAYED_DELIVERY_NOTICE.value}: return EndpointQualityUpdate( affected_email_address=address.lower(), reachability="degraded", last_failure_at=observed_at, reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) if message_class == MessageClass.COMPLAINT_OR_ABUSE.value: return EndpointQualityUpdate( affected_email_address=address.lower(), suppression_state="suppressed", last_failure_at=observed_at, reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) if message_class == MessageClass.UNSUBSCRIBE_OR_OPT_OUT.value: return EndpointQualityUpdate( affected_email_address=address.lower(), suppression_state="opted_out", reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) if message_class == MessageClass.HUMAN_REPLY.value: return EndpointQualityUpdate( affected_email_address=address.lower(), last_success_at=observed_at, reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) if message_class == MessageClass.OUT_OF_OFFICE.value: return EndpointQualityUpdate( affected_email_address=address.lower(), reachability="uncertain", last_auto_reply_at=observed_at, reason_code=reason_code, confidence=candidate.confidence, quality_signals=[signal, candidate.event_type], ) return None