Developer Guides
Receiving email as application input
Inbound email lets an address become an entry point to your application: replies to a ticket, documents sent to a processing address, commands to a bot.
The mechanism is simple — mail arrives, you receive it as a webhook. The handling is where the work is.
The routing
Point an MX record at the receiving infrastructure, define which addresses or patterns route where, and each match delivers a parsed message to your endpoint.
Patterns matter more than fixed addresses. A ticketing system wants
ticket+{id}@, not one address per ticket. The sub-address after the plus
survives most mail systems and is the usual carrier for context.
MIME is worse than it looks
A real message is a tree. There is usually a plain-text part and an HTML part, often nested inside multipart containers, sometimes with attachments inside those, encoded in ways that vary by client and decade.
Use a parser. Writing one by hand looks feasible for a day and then you meet quoted-printable with soft line breaks inside a header that uses RFC 2047 encoding in a character set from 1995.
Things that will arrive and must not crash the handler: no text part at all, no subject, a From that does not parse, attachments with no filename, filenames containing path separators, and the same attachment declared twice.
Stripping quoted replies
If you are taking replies as input, most of the body is the previous conversation. Every client quotes differently — some prefix with angle brackets, some wrap in a div with a class, some do neither and just include everything.
There is no reliable rule. Heuristics get most of it; keep the full original so a mis-strip can be recovered rather than being a silent data loss.
The From header is a claim, not a fact
This is the part people underestimate. Anyone can put anything in a From header. If your handler trusts it to identify a user, anyone who knows a customer's address can act as that customer.
Check the authentication results on the inbound message: did SPF pass, did DKIM pass, did either align with the claimed domain? A message failing DMARC for a domain that publishes a policy should not be treated as being from that domain.
For anything that mutates state, authentication alone is still thin. Put an
unguessable token in the address — ticket+{id}-{hmac}@ — so possession of a
routable address is itself evidence.
Everything else about untrusted input
Attachments are files from strangers. Scan them, cap the size, and store them somewhere that does not execute anything. Filenames are attacker-controlled: generate your own and keep the original as a label.
HTML bodies are untrusted markup. Sanitise before rendering anywhere.
Responding
Return 200 quickly and process asynchronously; a slow handler gets the same message again. Deduplicate on the Message-ID, because retries and forwarding loops both produce duplicates.
And be careful about auto-replying. A reply to an address that also auto-replies is a
loop, which is what the Auto-Submitted header and precedence conventions
exist to prevent. Honour them, and set them on anything you send automatically.
DKIM signing, SPF alignment and DMARC are set up the moment you verify a domain.