# `Letterbox.MIME`
[🔗](https://github.com/hattoriai/letterbox/blob/v0.1.0-rc.0/lib/letterbox/mime.ex#L1)

An email's structure (MIME, RFC 2045 to 2049): its parts, their headers
and their bodies, still encoded.

    part = Letterbox.MIME.parse(raw)
    part.type          #=> "multipart/mixed"
    Enum.map(part.parts, & &1.type)
    #=> ["multipart/alternative", "image/jpeg"]

Parsing copies nothing: each part's `:body` is a sub-binary of `raw`,
the bytes where they are. A body is decoded only when it is asked for:
a text with `text/1`, any body with `decode/1`, and an attachment as a
stream of chunks with `stream/2`, so a photograph of 8 MB goes to a file
without its decoded bytes ever all in memory.

The parser takes what mail clients send: `LF` as well as `CRLF`, a
multipart with no closing boundary, a part with no headers, a boundary
in quotes or not. It stops where an email would make it work without
end: past `:max_depth` levels of parts in parts (20) or `:max_parts`
parts (1,000), the rest of a multipart is one part of its type, not
split.

# `t`

```elixir
@type t() :: %Letterbox.MIME{
  body: binary(),
  content_id: String.t() | nil,
  disposition: String.t() | nil,
  disposition_params: %{required(String.t()) =&gt; String.t()},
  encoding: String.t(),
  headers: [Letterbox.MIME.Header.t()],
  params: %{required(String.t()) =&gt; String.t()},
  parts: [t()],
  path: [non_neg_integer()],
  type: String.t()
}
```

A part:

  * `:type` - its content type, in lowercase (`"text/plain"` when it
    has none, as RFC 2045 says).
  * `:params` - the content type's parameters (`"charset"`,
    `"boundary"`, `"name"`), decoded.
  * `:disposition` - `"attachment"`, `"inline"`, or nil when it has none,
    and `:disposition_params` (`"filename"`, decoded).
  * `:encoding` - its `Content-Transfer-Encoding`, in lowercase:
    `"base64"`, `"quoted-printable"`, `"7bit"`, `"8bit"`, `"binary"`.
  * `:content_id` - its `Content-ID`, without the angle brackets: what
    an HTML part's `cid:` points to.
  * `:headers` - all its headers (`Letterbox.MIME.Header.parse/1`).
  * `:body` - its body, still encoded, a sub-binary of the email.
  * `:parts` - the parts of a multipart, and the one email of a
    `message/rfc822` (a forwarded email, attached).
  * `:path` - where it is: `[]` for the email, `[1, 0]` for the first
    part of the second.

# `decode`

```elixir
@spec decode(t()) :: binary()
```

A part's body, decoded from its transfer encoding: the bytes it carries.

# `leaves`

```elixir
@spec leaves(t()) :: [t()]
```

Every part with no parts of its own (the texts, images, files), in the
order a reader meets them, a `message/rfc822` included as one.

# `parse`

```elixir
@spec parse(binary(), keyword()) :: t()
```

The structure of an email, `raw` as it came (RFC 5322).

Options: `:max_depth` (20) and `:max_parts` (1,000).

# `stream`

```elixir
@spec stream(t(), keyword()) :: Enumerable.t()
```

A part's body, decoded, as a stream of chunks: for a large attachment,
written to a file as it is decoded. `:chunk` is how many bytes of the
encoded body each chunk is decoded from (64 KB).

# `text`

```elixir
@spec text(t()) :: {:ok, String.t()} | {:lossy, String.t()}
```

A text part's body in UTF-8, from its charset, with its line breaks as
`\n`: `{:ok, text}`, or `{:lossy, text}` when bytes of it could not be
read (see `Letterbox.Charset`).

---

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