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
- RFC 2047 encoded-word headers: Non-ASCII subject lines and display names arrive encoded as
=?charset?encoding?encoded-text?=(eitherQfor quoted-printable orBfor base64), often split across multiple folded header lines with intervening whitespace that must be collapsed during decoding. - Quoted-Printable soft line breaks: RFC 2045 mandates that lines in
quoted-printablebodies must not exceed 76 characters; long URLs (such as magic login links or OAuth callback tokens) are split with a trailing=followed byCRLF, and literal=characters in query strings are encoded as=3D. Failing to decode=3Dbefore rendering breaks every verification link in the email. - Charset normalization: Legacy financial and enterprise mailers still emit
windows-1252,iso-8859-1, oriso-2022-jpparts. Decoding those byte slices throughnew 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
- How tenmin.app works under the hood: ephemeral edge email architecture covers the full system architecture across inbound SMTP routing, lease validation, and storage.
- Preventing XSS when rendering untrusted HTML emails in a browser explains what happens to the parsed
htmlstring once it reaches the frontend viewer. - How to test SPF, DKIM, and DMARC records in staging environments walks through inspecting the raw MIME and authentication headers of your own outbound mail.
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.