MIME parsing¶
mxRaven webhook payloads describe inbound mail as JSON, but the full message is
kept as raw RFC 5322 bytes behind the payload's raw_email reference.
mxraven.mime turns those bytes into headers, addresses, bodies, and decoded
attachments. It uses only the standard library.
Parse bytes you already hold¶
from mxraven.mime import parse_email
email = parse_email(raw_bytes)
print(email.subject, len(email.attachments))
for attachment in email.attachments:
print(attachment.filename, attachment.content_type, len(attachment.content))
Fetch and parse in one step¶
from mxraven.mime import fetch_and_parse_raw_email
from mxraven.webhook import EventType, Verifier
verifier = Verifier(secret=signing_secret)
event = verifier.verify_and_decode(request)
if event.type is EventType.INBOUND_EMAIL and event.inbound_email is not None:
email = fetch_and_parse_raw_email(event.inbound_email.raw_email)
print(email.subject, email.text)
The download verifies the declared size and SHA-256 digest and sends the
payload's short-lived bearer token in the Authorization header. Do not log
that token.
The asyncio counterpart lives in mxraven.aio.mime:
from mxraven.aio.mime import fetch_and_parse_raw_email
email = await fetch_and_parse_raw_email(event.inbound_email.raw_email)
Parsed message¶
ParsedEmail carries:
| Field | Meaning |
|---|---|
headers |
Every header field, in order, with continuation lines unfolded. Values are not decoded. |
subject |
The decoded Subject. |
from_, to, cc, bcc, reply_to |
Parsed mailboxes with decoded display names. |
message_id |
The Message-ID without angle brackets. |
date |
The parsed Date, when present and parseable. |
text, html |
The first decoded text/plain and text/html bodies. |
attachments |
Every non-body part with decoded content, filename, content type, and Content-ID. |
ParsedAttachment.inline is true when a part is marked inline or carries a
Content-ID, which is how an inline image referenced by cid: from an HTML
body is identified.
Parser behavior¶
The parser is defensive: malformed messages yield the best available
interpretation instead of an error. It understands multipart/mixed,
multipart/alternative, and multipart/related, decodes base64 and
quoted-printable transfer encodings, decodes RFC 2047 encoded words, and
reassembles RFC 2231 parameters. Declared charsets are decoded; unknown charsets
fall back to UTF-8 and then Windows-1252. message/rfc822 parts are surfaced as
attachments rather than parsed recursively.
Only structurally unbounded input is rejected, so an untrusted message cannot exhaust the stack or memory:
| Error | Meaning |
|---|---|
MimeNestingError |
MIME nesting exceeds 20 levels. |
MimePartsError |
More than 2000 MIME entities. |