mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-11-11 03:11:33 +00:00
Python 3.10 reaches end of life in October 2026. requires-python is now >=3.11, the unused requires_python key under [build-system] (not read by hatchling, and its <3.15 bound read as excluding 3.15) is removed, and Python 3.15 joins the CI matrix, classifiers, and support tables. Docs, AGENTS.md, and comments that named 3.10 as the floor are updated. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
239 lines
5.4 KiB
Python
239 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Literal, TypedDict
|
|
|
|
# NOTE: This module targets Python 3.11.
|
|
# - PEP 604 unions (A | B) and PEP 585 generics (list[str]) are used.
|
|
# - typing.NotRequired / Required are available (3.11+), but this module keeps
|
|
# total=False TypedDicts for optional keys; keep one style per module.
|
|
|
|
|
|
ReportType = Literal["aggregate", "failure", "smtp_tls"]
|
|
|
|
|
|
class AggregateReportMetadata(TypedDict):
|
|
org_name: str
|
|
org_email: str
|
|
org_extra_contact_info: str | None
|
|
report_id: str
|
|
begin_date: str
|
|
end_date: str
|
|
timespan_requires_normalization: bool
|
|
original_timespan_seconds: int
|
|
errors: list[str]
|
|
generator: str | None
|
|
|
|
|
|
class AggregatePolicyPublished(TypedDict):
|
|
domain: str
|
|
adkim: str
|
|
aspf: str
|
|
p: str
|
|
sp: str
|
|
pct: str | None
|
|
fo: str | None
|
|
np: str | None
|
|
testing: str | None
|
|
discovery_method: str | None
|
|
|
|
|
|
class IPSourceInfo(TypedDict):
|
|
ip_address: str
|
|
country: str | None
|
|
reverse_dns: str | None
|
|
base_domain: str | None
|
|
name: str | None
|
|
type: str | None
|
|
asn: int | None
|
|
as_name: str | None
|
|
as_domain: str | None
|
|
|
|
|
|
class AggregateAlignment(TypedDict):
|
|
spf: bool
|
|
dkim: bool
|
|
dmarc: bool
|
|
|
|
|
|
class AggregateIdentifiers(TypedDict):
|
|
header_from: str
|
|
envelope_from: str | None
|
|
envelope_to: str | None
|
|
|
|
|
|
class AggregatePolicyOverrideReason(TypedDict):
|
|
type: str | None
|
|
comment: str | None
|
|
|
|
|
|
class AggregateAuthResultDKIM(TypedDict):
|
|
domain: str
|
|
result: str
|
|
selector: str
|
|
human_result: str | None
|
|
|
|
|
|
class AggregateAuthResultSPF(TypedDict):
|
|
domain: str
|
|
result: str
|
|
scope: str
|
|
human_result: str | None
|
|
|
|
|
|
class AggregateAuthResults(TypedDict):
|
|
dkim: list[AggregateAuthResultDKIM]
|
|
spf: list[AggregateAuthResultSPF]
|
|
|
|
|
|
class AggregatePolicyEvaluated(TypedDict):
|
|
disposition: str
|
|
dkim: str
|
|
spf: str
|
|
policy_override_reasons: list[AggregatePolicyOverrideReason]
|
|
|
|
|
|
class AggregateRecord(TypedDict):
|
|
interval_begin: str
|
|
interval_end: str
|
|
source: IPSourceInfo
|
|
count: int
|
|
alignment: AggregateAlignment
|
|
policy_evaluated: AggregatePolicyEvaluated
|
|
disposition: str
|
|
identifiers: AggregateIdentifiers
|
|
auth_results: AggregateAuthResults
|
|
|
|
|
|
class AggregateReport(TypedDict):
|
|
xml_schema: str
|
|
xml_namespace: str | None
|
|
report_metadata: AggregateReportMetadata
|
|
policy_published: AggregatePolicyPublished
|
|
records: list[AggregateRecord]
|
|
|
|
|
|
class EmailAddress(TypedDict):
|
|
display_name: str | None
|
|
address: str
|
|
local: str | None
|
|
domain: str | None
|
|
|
|
|
|
class EmailAttachment(TypedDict, total=False):
|
|
filename: str | None
|
|
mail_content_type: str | None
|
|
sha256: str | None
|
|
|
|
|
|
ParsedEmail = TypedDict(
|
|
"ParsedEmail",
|
|
{
|
|
# This is a lightly-specified version of mailsuite/mailparser JSON.
|
|
# It focuses on the fields parsedmarc uses in failure report handling.
|
|
"headers": dict[str, Any],
|
|
"subject": str | None,
|
|
"filename_safe_subject": str | None,
|
|
"date": str | None,
|
|
"from": EmailAddress,
|
|
"to": list[EmailAddress],
|
|
"cc": list[EmailAddress],
|
|
"bcc": list[EmailAddress],
|
|
"attachments": list[EmailAttachment],
|
|
"body": str | None,
|
|
"has_defects": bool,
|
|
"defects": Any,
|
|
"defects_categories": Any,
|
|
},
|
|
total=False,
|
|
)
|
|
|
|
|
|
class FailureReport(TypedDict):
|
|
feedback_type: str | None
|
|
user_agent: str | None
|
|
version: str | None
|
|
original_envelope_id: str | None
|
|
original_mail_from: str | None
|
|
original_rcpt_to: str | None
|
|
arrival_date: str
|
|
arrival_date_utc: str
|
|
authentication_results: str | None
|
|
delivery_result: str | None
|
|
auth_failure: list[str]
|
|
authentication_mechanisms: list[str]
|
|
dkim_domain: str | None
|
|
reported_domain: str
|
|
sample_headers_only: bool
|
|
source: IPSourceInfo
|
|
sample: str
|
|
parsed_sample: ParsedEmail
|
|
|
|
|
|
# Backward-compatible alias
|
|
ForensicReport = FailureReport
|
|
|
|
|
|
class SMTPTLSFailureDetails(TypedDict):
|
|
result_type: str
|
|
failed_session_count: int
|
|
|
|
|
|
class SMTPTLSFailureDetailsOptional(SMTPTLSFailureDetails, total=False):
|
|
sending_mta_ip: str
|
|
receiving_ip: str
|
|
receiving_mx_hostname: str
|
|
receiving_mx_helo: str
|
|
additional_info_uri: str
|
|
failure_reason_code: str
|
|
ip_address: str
|
|
|
|
|
|
class SMTPTLSPolicySummary(TypedDict):
|
|
policy_domain: str
|
|
policy_type: str
|
|
successful_session_count: int
|
|
failed_session_count: int
|
|
|
|
|
|
class SMTPTLSPolicy(SMTPTLSPolicySummary, total=False):
|
|
policy_strings: list[str]
|
|
mx_host_patterns: list[str]
|
|
failure_details: list[SMTPTLSFailureDetailsOptional]
|
|
|
|
|
|
class SMTPTLSReport(TypedDict):
|
|
organization_name: str
|
|
begin_date: str
|
|
end_date: str
|
|
contact_info: str | list[str]
|
|
report_id: str
|
|
policies: list[SMTPTLSPolicy]
|
|
|
|
|
|
class AggregateParsedReport(TypedDict):
|
|
report_type: Literal["aggregate"]
|
|
report: AggregateReport
|
|
|
|
|
|
class FailureParsedReport(TypedDict):
|
|
report_type: Literal["failure"]
|
|
report: FailureReport
|
|
|
|
|
|
# Backward-compatible alias
|
|
ForensicParsedReport = FailureParsedReport
|
|
|
|
|
|
class SMTPTLSParsedReport(TypedDict):
|
|
report_type: Literal["smtp_tls"]
|
|
report: SMTPTLSReport
|
|
|
|
|
|
ParsedReport = AggregateParsedReport | FailureParsedReport | SMTPTLSParsedReport
|
|
|
|
|
|
class ParsingResults(TypedDict):
|
|
aggregate_reports: list[AggregateReport]
|
|
failure_reports: list[FailureReport]
|
|
smtp_tls_reports: list[SMTPTLSReport]
|