Standalone, never-raising RFC 5322 MIME parser.
parse/1 turns a canonical raw MIME body into a stable internal
representation, or returns a structured MailglassInbound.MIMEError. It
never raises (MIME-04): the underlying gen_smtp mimemail decoder
escapes through three mechanisms (erlang:error, throw, and
:exit/:undef from iconv), all of which are absorbed by the
Mailglass.OptionalDeps.GenSmtp gateway seam and translated into
{:error, %MailglassInbound.MIMEError{}}.
Contract
@spec parse(binary()) :: {:ok, repr} | {:error, MailglassInbound.MIMEError.t()}{:ok, repr}—repris%{headers: ..., parts: ..., attachments: ..., inline: ...}(see Internal representation below).{:error, %MIMEError{type: :inbound_mime_invalid}}— the raw source could not be parsed (any of the three escape mechanisms, or the representation exceeded:max_depth).:causecarries the tagged gateway failure;:contextcarries%{byte_size: byte_size(raw)}.{:error, %MIMEError{type: :gen_smtp_unavailable}}— the optionalgen_smtpdependency is not loaded; MIME parsing is unavailable (MIME-02degraded fallback).
Note
The :max_depth option bounds the depth of the internal representation
walk — collect_leaves/3 re-walking the already-decoded tree — and gives
a deterministic structured ceiling on what the pipeline iterates. It does
not limit the underlying :mimemail decoder recursion: decode_and_build/2
calls the decoder first, which fully parses to any depth before the guard
ever runs. So :max_depth does not by itself defend against
provider-fed deep-nesting (boundary-bomb) DoS.
Provider-fed DoS hardening — a real decoder-level recursion limit — is a Phase 46 concern that will plug into this same seam. The guard is kept because it is that seam and because it bounds the representation the pipeline iterates.
Internal representation
parse/1 returns a map with four keys:
:headers— the top-level decoded header proplist ([{binary, binary}]).:parts— a flattened list of non-attachment, non-inline leaf parts. Each part is%{type, subtype, headers, params, body}wherebodyis the raw (untranscoded) leaf bytes.:attachments— leaf parts whoseContent-Dispositionisattachment. Each carries a resolved:filename(disposition_params["filename"] || content_type_params["name"]).:inline— leaf parts whoseContent-Dispositionis explicitlyinlineand which carry a filename (typicallyContent-IDimages). Inline text leaves without a filename land in:parts.
Standalone — not wired into any provider path
This parser is the producer only (D-45-18). It is NOT wired into the
working JSON-based Postmark/SendGrid normalize paths in this phase. Phase 46
(Mailgun/SES raw-MIME ingress) is the first consumer.
Encoding note
The gateway passes {:encoding, :none} to the decoder (gen_smtp does not
bundle iconv), so leaf :body bytes are not transcoded to UTF-8. A consumer
that needs UTF-8 text must transcode using the part's declared charset
(content_type_params["charset"]). Flagged for Phase 46.
Summary
Types
A single decoded leaf or container part in the internal representation.
Functions
Parses a raw RFC 5322 MIME body. See the moduledoc for the full contract.
Parses a raw RFC 5322 MIME body with options.
Types
@type part() :: %{ type: binary(), subtype: binary(), headers: [{binary(), binary()}], params: map(), body: term() }
A single decoded leaf or container part in the internal representation.
@type repr() :: %{ headers: [{binary(), binary()}], parts: [part()], attachments: [part()], inline: [part()] }
The stable internal representation returned by parse/1.
Functions
@spec parse(binary()) :: {:ok, repr()} | {:error, MailglassInbound.MIMEError.t()}
Parses a raw RFC 5322 MIME body. See the moduledoc for the full contract.
Equivalent to parse(raw, []).
@spec parse( binary(), keyword() ) :: {:ok, repr()} | {:error, MailglassInbound.MIMEError.t()}
Parses a raw RFC 5322 MIME body with options.
Options
:max_depth— maximum multipart nesting depth before the representation-depth guard trips and returns:inbound_mime_invalid(default100). See the moduledoc note on what this guard does and does not bound.:gen_smtp_available?— overrides the gateway availability check (testing seam for theMIME-02degraded path). Defaults toMailglass.OptionalDeps.GenSmtp.available?/0.