All dispatchesView as Markdown

Inbound email processing: parse replies and attachments safely

MC
Maya ChenEmail infrastructure at Email Bump

Route inbound email into an application with verified webhooks, durable raw-message storage, MIME parsing, reply tokens, loop prevention, attachment isolation, and idempotent workflows.

Inbound email processing turns messages sent to an application-owned address into structured events. Common uses include replying to support tickets, commenting on a project, approving a workflow, ingesting invoices, receiving application attachments, and giving an AI agent a mailbox. The provider receives SMTP, parses the message, and sends your application a webhook or API event.

Treat every inbound message as hostile, ambiguous input. The From header is not authorization, display names are not identity, HTML is untrusted markup, attachments are uploads, quoted text is heuristic, and the same provider event can be delivered more than once. Preserve evidence before deriving actions.

Inbound email architecture

Receive, preserve, then interpret
PUBLIC DNS MX
  routes inbound.example.com to provider
        |
        v
INBOUND PROVIDER
  receives SMTP -> assigns message/event ID -> parses envelope + MIME
        | signed webhook
        v
EDGE HANDLER
  verify signature on raw body -> enforce size -> deduplicate -> store raw evidence
        | acknowledge quickly
        v
DURABLE QUEUE
  malware/type checks -> MIME normalization -> routing -> authorization
        |
        v
APPLICATION WORKFLOW
  ticket reply / comment / document review / agent inbox / quarantine
        |
        v
AUDIT + OUTBOUND RESPONSE
  record decision; prevent loops; preserve thread identifiers

Choose the address model

Inbound address patterns
PATTERN                         USE
reply+<opaque-token>@in.example   Route one reply to a known conversation
ticket-<public-id>@support.example Human-readable support intake
<agent-id>@agents.example        Dedicated software or AI mailbox
upload+<token>@files.example     Controlled document ingestion
[email protected]             Avoid unless unknown-address policy is explicit

Use opaque, scoped routing tokens—not sequential database IDs or serialized secrets.
A routing token locates context; it should not automatically authorize risky actions.

A reply token can bind the recipient address to a conversation, tenant, expected participant, purpose, and expiration. Store a verifier server-side and rotate or revoke it when the thread closes. Reject or quarantine unknown recipient patterns instead of silently creating records in an arbitrary account.

Verify the provider webhook first

  • Read the raw HTTP body under a strict request-size limit before generic JSON or form parsing changes it.
  • Verify the provider’s current signature scheme, timestamp, and replay window using a dedicated inbound secret.
  • Reject invalid signatures with no downstream side effects and do not log the full body.
  • Deduplicate the provider event ID and retain the provider message ID separately.
  • Store or queue durable evidence before returning success; acknowledge quickly enough to avoid unnecessary retries.
  • Rotate secrets with an overlap procedure and distinguish test, staging, and production endpoints.

Webhook verification proves that the selected provider sent the request. It does not prove that fields inside the email are truthful. Authentication-Results can also be provider-generated evidence, but preserve the raw message and trust boundary so later investigators know which system evaluated it.

Preserve the raw message and normalized view

Inbound message record
provider_event_id      webhook deduplication key
provider_message_id    provider trace identifier
raw_object_key         encrypted immutable MIME/object reference
raw_sha256             integrity and duplicate evidence
envelope_from/to       SMTP routing identities
header_from/reply_to   display and reply identities
message_id             RFC message identifier; not globally trustworthy
in_reply_to/references thread hints
auth_results           parsed SPF/DKIM/DMARC/ARC evidence + raw source
subject/text/html      normalized bounded representations
attachments            quarantined object IDs + claimed/detected types + hashes
routing_token          scoped internal route after validation
processing_state       received | quarantined | routed | rejected | completed

Keep raw MIME because parsers change and normalized fields can lose evidence. Access should be restricted and retention deliberate: raw mail may contain credentials, health or financial data, signatures, hidden recipients, long conversation history, and attachments. Encrypt storage and separate support-visible summaries from full-source access.

Parse MIME defensively

  • Use a maintained MIME parser and bound total bytes, header count, line length, nesting depth, part count, and decompression work.
  • Expect multipart/alternative, multipart/related, nested messages, unusual charsets, malformed boundaries, and repeated headers.
  • Select a plain-text and HTML representation by policy; do not concatenate every alternative and duplicate content.
  • Decode transfer encoding and charset with explicit error handling while preserving original bytes.
  • Sanitize HTML for the exact rendering surface or display escaped plain text by default.
  • Never execute remote images, scripts, forms, embedded objects, or active attachment content in an operator view.
  • Treat Content-Type, filename, and extension as claims; compare them with allowed types and content inspection.

RFC 2045 defines MIME content types and transfer encodings, but syntactic MIME validity is not a security verdict. Messages found in the wild are frequently malformed. Decide whether each defect leads to bounded recovery, quarantine, or rejection rather than letting parser exceptions retry forever.

Treat attachments like public file uploads

Attachment handling path
decode under byte budget
  -> hash and assign server-generated object ID
  -> store outside executable/web root
  -> detect type and validate allowed extension/content
  -> scan or disarm under organization policy
  -> quarantine until checks complete
  -> expose through authenticated, authorized download
  -> expire under retention policy

Never interpolate the sender's filename into a filesystem path or shell command.

OWASP’s file-upload guidance recommends allowlisting extensions, distrusting Content-Type, generating storage filenames, imposing size limits, restricting authorization, storing files separately, and applying antivirus or content disarm where appropriate. Inbound email is another public upload channel and needs the same controls.

Extract replies without deleting evidence

Quoted-reply extraction is heuristic because clients use different separators, languages, HTML structures, and mobile signatures. Store the normalized full text, then derive a reply candidate with the parser version and confidence. Let support recover the full message when the heuristic removes meaningful content.

Do not use the subject alone for threading. Prefer a scoped reply address plus validated internal state; use In-Reply-To, References, and Message-ID as supporting hints. Message-ID values can be missing, duplicated, malformed, or attacker-controlled.

Authorize the application action

Progressive trust model
LOW RISK
Attach message to a quarantined support intake; human reviews

MEDIUM RISK
Add comment when routing token, expected participant, account state, and policy agree

HIGH RISK
Approve payment, change permissions, reset credentials, export data, or run tools
Require an authenticated in-product confirmation or stronger factor

Email authentication and a matching From address can raise confidence. They do not
turn an email into unrestricted command execution.

Prevent mail loops and automated storms

  • Detect null envelope senders and common auto-submitted, precedence, vacation, and delivery-status signals.
  • Do not auto-reply to bounces, complaints, out-of-office messages, or another automated response by default.
  • Stamp outbound application mail with stable Message-ID and loop-detection metadata where appropriate.
  • Cap automatic messages per conversation, account, sender, and time window.
  • Maintain a hop or automation budget when agents or integrations can email one another.
  • Require human or in-product confirmation before external side effects or tool execution.

Make processing idempotent

Providers retry webhooks, senders retry messages, and forwarding can create multiple copies. Deduplicate provider events exactly, then apply a second business-level policy using raw-message hash, routing token, Message-ID, sender evidence, and time window. Do not globally collapse messages only because Message-ID matches; legitimate resend and broken clients exist.

Effective-once inbound workflow
receive provider event N times
  -> one stored event row by provider_event_id
  -> one parse job by raw object/version
  -> one proposed business action by inbound_action_key
  -> zero or one authorized state transition
  -> one outbound acknowledgement by transition key

Keep transport duplication, message duplication, and business idempotency separate.

Test the hostile cases

  • Invalid and replayed webhook signatures, duplicate events, and out-of-order provider notifications.
  • Oversized request, excessive MIME nesting, huge headers, many tiny parts, and decompression bombs.
  • Forged From and Reply-To, failed authentication, multiple Authentication-Results, and misleading display names.
  • HTML injection, tracking pixels, remote content, dangerous URLs, and bidirectional Unicode controls.
  • Executable, macro, archive, double-extension, path-like, and mismatched-type attachments.
  • Unknown, expired, cross-tenant, already-used, and revoked reply tokens.
  • Vacation responder, bounce, complaint, delivery notification, and agent-to-agent mail loops.

Frequently asked questions

What is inbound email processing?

It is the receipt, parsing, routing, and application handling of email sent to an address your software owns. A provider normally accepts SMTP and sends structured content or a raw-message reference to your webhook; your application then validates and authorizes any resulting workflow.

What is email parsing?

Email parsing converts raw Internet Message Format and MIME into fields such as envelope recipients, headers, HTML, text, and attachments. Parsing explains structure; it does not establish sender identity, attachment safety, or permission to act.

Can an inbound email create a support ticket automatically?

Yes, if the system verifies the provider event, safely stores and parses the message, applies tenant and abuse rules, deduplicates the action, and quarantines risky content. Higher-impact actions should require stronger authenticated confirmation.