Technical GuideUpdated 2026-10-22

How RFC 5322 MIME parsing works in serverless edge environments

By Koracle LLC EngineeringSystems Architect··13 min read
serverlessarchitecturetechnicaldeveloper

An email message in transit is not a JSON object with subject and body fields. It is a raw byte stream formatted according to RFC 5322 (Internet Message Format) and RFC 2045 to 2049 (Multipurpose Internet Mail Extensions, or MIME). When you process incoming mail inside a stateless serverless isolate at the network edge, you have to parse nested multipart boundaries, decode transfer encodings, normalize legacy character sets, and enforce strict memory bounds inside a runtime with a tight RAM ceiling.

Here is how RFC 5322 and multipart MIME parsing work in constrained serverless environments and the defensive patterns used to keep inbound email processing fast and predictable.

The anatomy of a multipart MIME envelope

A modern transactional email almost never consists of a single body block. Instead, the top-level Content-Type header declares a recursive tree of MIME parts separated by unique boundary strings:

From: "Billing Service" <billing@example.com>
To: a1b2c3@tenmin.app
Subject: =?UTF-8?B?Your_invoice_is_ready_=E2=9C=93?=
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="mix-boundary-9f8e"

--mix-boundary-9f8e
Content-Type: multipart/alternative; boundary="alt-boundary-3a1c"

--alt-boundary-3a1c
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

Your verification code is 482910.=20
Valid for 10 minutes.

--alt-boundary-3a1c
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64

PGh0bWw+PGJvZHk+PHA+WW91ciB2ZXJpZmljYXRpb24gY29kZSBpcyA8c3Ryb25nPjQ4MjkxMDwv
c3Ryb25nPi48L3A+PC9ib2R5PjwvaHRtbD4=
--alt-boundary-3a1c--

--mix-boundary-9f8e
Content-Type: application/pdf; name="invoice.pdf"
Content-Disposition: attachment; filename="invoice.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MKNCAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDMgMCBS...
--mix-boundary-9f8e--

A compliant parser must walk this tree, distinguish multipart/alternative branches (where text/plain and text/html represent the same content at different fidelity levels) from multipart/mixed attachments and multipart/related inline CID images, and decode each leaf node according to its own Content-Transfer-Encoding and charset parameters.

Constraints of serverless V8 isolates

Traditional Node.js email parsers were designed for long-lived Linux containers with gigabytes of heap headroom. Many rely on legacy stream transforms, mutable buffers, and heavyweight character-set lookup tables that can allocate tens of megabytes per concurrent message.

In a modern edge isolate runtime, inbound SMTP handlers operate under much stricter bounds:

  • The raw message body arrives as a standard Web ReadableStream<Uint8Array> rather than a Node filesystem stream.
  • Each isolate typically enforces a 128 MB memory limit across active invocations. Buffering a 25 MB attachment three times in memory (raw bytes, base64 string, decoded binary) will trigger an immediate out-of-memory isolate termination.
  • Unbounded regular expressions on malformed MIME boundaries or deeply nested multipart bombs can exhaust the per-invocation CPU budget in milliseconds.

Reading the raw stream with defensive bounds

Before handing bytes to a MIME parser, an inbound handler should validate the recipient address and active lease state at the envelope layer so invalid traffic is rejected via SMTP 550 before any stream allocation occurs:

export async function handleInboundEmail(envelope, storage) {
  const localPart = String(envelope.to || "").split("@")[0].trim().toLowerCase();
  if (!/^[0-9a-f]{6}$/.test(localPart)) {
    envelope.reject("550 5.1.1 Invalid recipient");
    return;
  }

  // Read Web ReadableStream into a bounded Uint8Array
  const reader = envelope.rawStream.getReader();
  const chunks = [];
  let totalBytes = 0;

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    totalBytes += value.byteLength;
    if (totalBytes > 10 * 1024 * 1024) {
      envelope.reject("552 5.3.4 Message exceeds maximum size limit");
      return;
    }
    chunks.push(value);
  }

  const rawBytes = new Uint8Array(totalBytes);
  let offset = 0;
  for (const chunk of chunks) {
    rawBytes.set(chunk, offset);
    offset += chunk.byteLength;
  }

  const parsed = await parseMimeEnvelope(rawBytes);
  // Persist bounded text/html parts with 600s TTL...
}

Rejecting invalid recipients and oversized payloads during the SMTP transaction returns an explicit permanent error code to the sending MTA rather than silently dropping the message. Legitimate senders get immediate delivery feedback while abusive traffic is shed at zero storage cost.

Zero-copy typed-array parsing and native TextDecoder

For edge isolate environments, a streaming or zero-copy MIME parser operating directly on ArrayBuffer and Uint8Array views avoids redundant string allocations. Instead of bundling megabytes of JavaScript character-encoding tables, modern runtimes expose the WHATWG TextDecoder API backed by native C++ ICU routines.

Three tricky edge cases every parser must handle

  1. RFC 2047 encoded-word headers: Non-ASCII subject lines and display names arrive encoded as =?charset?encoding?encoded-text?= (either Q for quoted-printable or B for base64), often split across multiple folded header lines with intervening whitespace that must be collapsed during decoding.
  2. Quoted-Printable soft line breaks: RFC 2045 mandates that lines in quoted-printable bodies must not exceed 76 characters; long URLs (such as magic login links or OAuth callback tokens) are split with a trailing = followed by CRLF, and literal = characters in query strings are encoded as =3D. Failing to decode =3D before rendering breaks every verification link in the email.
  3. Charset normalization: Legacy financial and enterprise mailers still emit windows-1252, iso-8859-1, or iso-2022-jp parts. Decoding those byte slices through new TextDecoder(charset) normalizes the output into clean UTF-8 strings before JSON serialization.

Bounding parsed output before storage

Even after successful MIME parsing, storing raw HTML or text blobs directly into a database without size truncation creates a row-size and memory hazard. A defensive ingestion pipeline caps subject lines at 998 characters (the RFC 5322 line length ceiling), limits per-inbox message count, and truncates extracted text and html bodies (for example, at 200 KB) before persisting the record with its expiration timestamp.

Further reading

Ready when you are

Need an ephemeral test inbox right now?

Generate a fresh @tenmin.app address in one click. Zero registration, sandboxed HTML rendering, automatic 600-second TTL deletion.