Inbound Email Processing Architecture: Route Messages Without Trusting Them
Design inbound email ingestion with owned addresses, authenticated callbacks, safe content handling and controlled conversation correlation.
TL;DR
- Treat inbound mail as untrusted input: separate ingestion from business action so a received message does not itself authorize account changes or execute instructions.
- Use explicit routing and authenticated callbacks: maintain a receiving-address map, verify provider signatures, persist unique observations, and retrieve full messages through the provider API when needed.
- Validate success by testing hostile and normal flows: exercise duplicate callbacks, unknown addresses, ambiguous threads and attachments while ensuring the system preserves evidence and enforces ownership rules.
Receiving a message does not authorize an action
Inbound email can power support inboxes, receipt processing and customer replies. It also brings untrusted content from outside the application. A message arriving at an owned address should be treated as input to evaluate, not as authority to change an account or execute instructions.
Separate ingestion from business action. The provider receives and parses mail; your application authenticates the callback, retains the message reference, determines the intended route and applies a constrained workflow. Sensitive actions may require confirmation through an authenticated product session.
This architecture avoids a common mistake: equating a visible From address with verified account ownership. Email context can help route a conversation, but it should not bypass the application's authorization rules.
Define the receiving-address map
Decide which domain or subdomain will receive application mail and which addresses map to supported workflows. Do not alter a domain's existing incoming-mail routing without understanding other mailboxes that depend on it.
SendDart documents receiving on verified customer domains and routing inbound events through email.received callbacks. Its receiving guide describes a broad receiving-domain behavior, making application-side routing important. Use the exact supported configuration for your account. SendDart receiving introduction.
Maintain an explicit address map. A support address may create or update tickets, while a document-ingestion address may accept only a narrow file workflow. Unknown addresses should have a deliberate policy rather than falling into a privileged default handler.
Authenticate and retain the callback
Verify the provider signature against the required original request bytes. Validate the event shape and persist a unique observation before performing slow work. A retried callback should resolve to the same inbound message rather than create several tickets.
Use the provider message identifier to retrieve the full message through the documented API when needed. Keep the retrieval bounded and preserve tenant scope. The callback's metadata and the full stored message serve different purposes; do not assume the initial event contains every attachment byte or complete body.
SendDart's SDK exposes received-message retrieval and related operations. Review those methods and their response types, especially binary attachment or raw-message helpers. SendDart SDK receiving methods.
Correlate conversations with evidence
A subject line alone is a weak thread identifier. Different customers can use the same subject, and clients can edit it. Message identifiers and reply-reference fields provide useful correlation evidence under the Internet Message Format, but the application must still enforce ownership and routing policy. RFC 5322.
Store the relationship between an outgoing application message and its conversation. When a reply arrives, match it through documented headers and the receiving address under the correct tenant. If correlation is ambiguous, create a reviewable unassigned item rather than attaching it to the first plausible customer.
Do not let a guessed thread grant access to private history. Before showing a conversation or taking action, use the application's authorization model. An email reply can be displayed as untrusted conversation content without being treated as a logged-in account session.
Handle bodies as untrusted display content
HTML email can contain active or misleading content. Render it through an appropriate sanitizer or isolated display strategy and avoid executing scripts or trusting remote resources. Keep a plain-text view where useful, but do not assume plain text is safe to use as commands or queries without validation.
Quoted history and signatures can make the new message difficult to identify. Preserve the original evidence while presenting a readable conversation view. Do not delete content irreversibly merely because an automated quote stripper thinks it is redundant.
If an AI system assists with classification or drafting, treat the email body as untrusted data. Instructions inside a received message must not override the application's tool permissions or reveal other customers' information.
Put attachments behind a controlled boundary
Limit attachment size and accepted types according to the workflow. Store files privately, generate safe storage names and scan or quarantine as appropriate. OWASP's file-upload guidance describes several controls relevant to handling untrusted files. OWASP file upload guidance.
Do not trust the filename extension or reported content type alone. A file called invoice.pdf is still untrusted input. Avoid rendering arbitrary attachments inline in an administrative origin without a deliberate isolation policy.
Retain only what the application needs and enforce authorization on downloads. A temporary provider URL should not become a permanent public link copied into a ticket. Record provenance and access decisions without placing attachment contents in generic logs.
Control replies and automated loops
If the application sends an automatic acknowledgment, ensure that duplicate inbound events do not produce repeated responses. Use a stable operation identity and a clear policy for automatic messages, bounces and other machine-generated input.
A reply action should use the documented receiving-reply operation or properly constructed message references, while preserving the approved sender and recipients. Do not blindly reply-all to every address extracted from untrusted headers.
Rate-limit conversation automation and provide a pause mechanism. Two automatic responders can otherwise create a feedback loop. Keep an audit trail showing which inbound message authorized each outgoing response.
Test the hostile and ordinary cases
Test duplicate callbacks, unknown receiving addresses, ambiguous threads, attachment-only messages, malformed HTML and oversized files. Also test normal long conversations so safety controls do not make legitimate support unusable.
A dependable inbound system does not merely parse email. It preserves evidence, routes under ownership rules and limits what untrusted content can cause. That foundation supports useful reply workflows without turning the inbox into an alternate authorization channel.
Related reading: Best Email API: Choose With a Production Acceptance Test.
Related reading: Email Verification APIs: Compare Results, Uncertainty and Integration.