# `MailglassInbound.MIME`
[🔗](https://github.com/szTheory/mailglass/blob/v2.3.0/lib/mailglass_inbound/mime.ex#L1)

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**: 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}` — `repr` is `%{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`). `:cause` carries the tagged gateway failure;
  `:context` carries `%{byte_size: byte_size(raw)}`.
- `{:error, %MIMEError{type: :gen_smtp_unavailable}}` — the optional
  `gen_smtp` dependency is not loaded; MIME parsing is unavailable
  (degraded fallback).

> #### Note {: .info}
>
> 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
> A **future** 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}` where `body` is the raw
  (untranscoded) leaf bytes.
- `:attachments` — leaf parts whose `Content-Disposition` is `attachment`.
  Each carries a resolved `:filename`
  (`disposition_params["filename"] || content_type_params["name"]`).
- `:inline` — leaf parts whose `Content-Disposition` is explicitly `inline`
  *and* which carry a filename (typically `Content-ID` images). Inline text
  leaves without a filename land in `:parts`.

## Standalone — not wired into any provider path

This parser is the **producer only**. It is NOT wired into the
working JSON-based Postmark/SendGrid normalize paths in this version; 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 as a future improvement.

# `part`

```elixir
@type part() :: %{
  type: binary(),
  subtype: binary(),
  headers: [{binary(), binary()}],
  params: map(),
  body: term()
}
```

A single decoded leaf or container part in the internal representation.

# `repr`

```elixir
@type repr() :: %{
  headers: [{binary(), binary()}],
  parts: [part()],
  attachments: [part()],
  inline: [part()]
}
```

The stable internal representation returned by `parse/1`.

# `parse`
*since 0.2.0* 

```elixir
@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, [])`.

# `parse`
*since 0.2.0* 

```elixir
@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`
  (default `100`). See the moduledoc note on what this
  guard does and does not bound.
- `:gen_smtp_available?` — overrides the gateway availability check (testing
  seam for the degraded path). Defaults to
  `Mailglass.OptionalDeps.GenSmtp.available?/0`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
