Why inbound email processing matters
Inbound email processing is the glue between user-facing email and your application logic. When customers reply to notifications, forward receipts, or email your support address, you need a reliable way of receiving, routing, and processing those messages programmatically. A good solution should accept email at stable addresses, normalize the raw MIME into developer-friendly JSON, and deliver it to your app by webhook or API with strong reliability guarantees.
This article compares MailParse and Twilio SendGrid's Inbound Parse on one capability only - inbound-email-processing. You will see how each handles receiving, routing, and processing, the payloads you get, edge cases, and the developer experience from code to production. For clarity, we will refer to MailParse as the platform throughout most of this guide.
If you are planning a new integration, the following resources pair well with this comparison:
- Top Inbound Email Processing Ideas for SaaS Platforms
- Email Infrastructure Checklist for SaaS Platforms
- Email Deliverability Checklist for SaaS Platforms
How the platform handles inbound email processing
MailParse focuses on instant receiving and parsing. You can provision unique email addresses by API in seconds, point users at those addresses, and the service handles SMTP for you. When a message arrives, the full MIME is decoded into structured JSON and delivered either by webhook or pulled via a REST polling API.
Address provisioning and routing
- Instant mailboxes - create individual addresses per user, organization, or workflow by API without touching DNS. Use tags or sub-addressing for flexible routing.
- Pattern routing - route by recipient, plus tags, or subject tokens. Configure rules so the right service or queue receives each message.
- Catchall support - handle unplanned recipients safely, useful for prototypes and testing.
Parsing depth
- Full MIME to JSON - headers are normalized, charsets decoded to UTF-8, and common encodings like quoted-printable and base64 are handled.
- Multiparts - nested multiparts are flattened into a predictable structure that includes text, HTML, calendar invites, and other specialized parts.
- Attachments - you receive attachment metadata and a direct download URL or inlined content depending on your configuration. Inline images include
contentIdwith cross references from HTML. - Threading -
messageId,inReplyTo, andreferencesare preserved for building conversation views and linking replies to tickets.
Webhook delivery and polling
- Webhook payload - a single JSON object that contains envelope data, normalized headers, decoded bodies, and attachments metadata. No multipart parsing is required on your side.
- Retries and idempotency - 2xx response is required, otherwise the platform retries with exponential backoff. Each delivery includes a stable
idso your API can de-duplicate safely. - REST polling - list messages by cursor or time window, acknowledge processing when complete, and reprocess on demand. Useful when you cannot expose public endpoints.
Typical webhook JSON shape
{
"id": "evt_01HX3A9Z1Z7GQ9VQ4D2M",
"receivedAt": "2026-04-21T14:25:31.144Z",
"envelope": {
"from": "alice@example.com",
"to": ["inbox+customer123@yourapp.mail"],
"recipients": ["inbox+customer123@yourapp.mail"],
"helo": "mail-qt1.example.org",
"remoteIp": "203.0.113.24"
},
"headers": {
"messageId": "<a1b2c3@example.com>",
"subject": "Invoice attached",
"date": "Tue, 21 Apr 2026 14:24:59 +0000",
"dkimSignature": "...",
"references": []
},
"body": {
"text": "Hi team,\nSee invoice attached.\n",
"html": "<p>Hi team,</p><p>See invoice attached.</p>",
"charset": "utf-8"
},
"attachments": [
{ "filename": "invoice.pdf", "contentType": "application/pdf", "size": 234567, "contentId": null, "sha256": "..." }
],
"spam": { "isSpam": false, "score": 0.2 }
}
How SendGrid Inbound Parse handles inbound email processing
Twilio SendGrid's inbound-email-processing feature is configured per domain or subdomain. You add MX records pointing to SendGrid, create an Inbound Parse setting, and specify a destination URL. When email arrives, SendGrid accepts it and POSTs data to your endpoint.
Setup and routing
- DNS based - you must control a domain, add MX records for a subdomain like
inbound.yourdomain.com, and route messages there. - Addressing - dynamic addressing is typically achieved with a catchall or plus addressing strategy. You cannot programmatically mint unique mailboxes, so you parse the recipient from the envelope.
- Spam handling - spam score fields are included. You decide whether to accept or discard based on your logic.
Payloads and options
- Multipart payload - SendGrid Inbound Parse posts
multipart/form-data. Text and HTML bodies arrive as form fields liketextandhtml, headers as a raw block, the envelope as a JSON string field, and attachments as file parts. - Raw mode - set
send_raw=1in the parse setting to receive the entire RFC 822 message as a singleemailfield. This is useful if you want to run your own MIME parser. - Size limit - typical limit is 30 MB including attachments. Large messages may be dropped before they reach your webhook.
- Reliability contract - your endpoint should return 2xx quickly. Inbound Parse expects synchronous confirmation and does not include built-in HMAC signatures. You can use Basic Auth, tokens in the URL, or IP allowlisting for verification.
Developer experience is straightforward if you already use Twilio SendGrid for outbound mail. The main tradeoff is that you will parse multipart webhooks and manage your own idempotency and retries. If you need structured JSON for every MIME part, you may run sendgrid-inbound-parse in raw mode and apply your own parser.
Side-by-side comparison of inbound email processing features
| Capability | The platform | SendGrid Inbound Parse |
|---|---|---|
| Address provisioning | Instant addresses via API, per user or workflow | DNS MX required on your domain, use catchall or plus addressing |
| Payload format | Single JSON object, decoded and normalized | multipart/form-data with fields and files, or raw RFC 822 |
| Parsing depth | Full MIME to structured JSON, inline CID linking, charset decoding | Basic fields or raw message, deeper parsing is your responsibility |
| Webhook retries | Exponential backoff with idempotency token | Best effort delivery that expects 2xx quickly, limited retry behavior |
| REST polling option | Yes, with cursors and acknowledgements | No, webhook only |
| Attachment handling | Metadata plus content or download URL, SHA-256 checksum | Files posted as multipart parts, you manage storage and hashing |
| Routing rules | Per-recipient pattern matching and plus-tag routing | Catchall via envelope parsing and custom logic |
| Security | Optional webhook signing and IP allowlisting | IP allowlisting and custom tokens, no built-in HMAC signature |
| Threading fields | messageId, inReplyTo, references normalized |
Available via headers field or raw message, you parse them |
Code examples
Receive JSON webhook from the platform (Node.js, Express)
import express from "express";
const app = express();
app.use(express.json({ limit: "10mb" }));
// Idempotent processing using event id
app.post("/webhooks/inbound", async (req, res) => {
const evt = req.body; // JSON payload
// evt.id is stable across retries
// Persist id to prevent duplicates
// Process message
console.log("From:", evt.envelope.from);
console.log("Subject:", evt.headers.subject);
console.log("Text:", evt.body.text);
for (const att of evt.attachments || []) {
console.log(`Attachment ${att.filename} ${att.contentType} ${att.size} bytes`);
// Download or stream if a URL is provided
}
// Respond fast to acknowledge
res.status(200).json({ ok: true });
});
app.listen(3000, () => console.log("Listening on 3000"));
Poll messages via REST when webhooks are not possible (Python)
import os
import requests
API_KEY = os.environ.get("INBOUND_API_KEY")
BASE_URL = "https://api.example.com/v1/inbound"
cursor = None
while True:
params = {"limit": 50}
if cursor:
params["cursor"] = cursor
r = requests.get(BASE_URL + "/messages", params=params, headers={"Authorization": f"Bearer {API_KEY}"})
r.raise_for_status()
data = r.json()
for msg in data["items"]:
print(msg["headers"]["subject"])
# Process...
ack = requests.post(BASE_URL + f"/messages/{msg['id']}/ack", headers={"Authorization": f"Bearer {API_KEY}"})
ack.raise_for_status()
cursor = data.get("nextCursor")
if not cursor:
break
Receive SendGrid Inbound Parse webhook (Node.js, Express + Multer)
import express from "express";
import multer from "multer";
const app = express();
const upload = multer({ limits: { fileSize: 30 * 1024 * 1024 } }); // 30 MB
// SendGrid posts multipart/form-data
app.post("/sendgrid/inbound", upload.any(), async (req, res) => {
// Text fields live in req.body
const from = req.body.from;
const to = req.body.to;
const subject = req.body.subject;
const text = req.body.text;
const html = req.body.html;
// The envelope is a JSON string field
let envelope = {};
try {
envelope = JSON.parse(req.body.envelope || "{}");
} catch {
envelope = {};
}
// Attachments are available in req.files
for (const file of req.files || []) {
console.log(`Attachment ${file.originalname} ${file.mimetype} ${file.size}`);
// file.buffer contains the content if memory storage is used
// Otherwise, stream to storage
}
// Acknowledge quickly, do heavy work asynchronously
res.status(200).send("OK");
});
app.listen(3001, () => console.log("Listening on 3001"));
Performance and reliability in production
Throughput and backpressure
Both services can handle large volumes if your endpoint responds quickly. The platform emphasizes fast acknowledgment and retries with exponential backoff, which helps you absorb bursts without losing messages. Use the idempotent event id to ensure exactly-once effects in your own system, even if deliveries are attempted more than once.
With SendGrid Inbound Parse, plan for synchronous handling. Respond with 2xx as fast as possible then enqueue the work. It is best practice to offload parsing and storage to a worker queue so your webhook stays responsive during traffic spikes.
Large messages and encodings
- Attachments - if your use case includes PDFs, images, or ICS files, test end-to-end at your maximum expected size. The platform emits size metadata and a checksum so you can verify integrity post-download. SendGrid posts files as part uploads, so compute your own checksums.
- Charsets and encodings - the platform decodes to UTF-8 before you see content. With SendGrid, you may receive text with quoted-printable artifacts or different charsets if you read headers directly. Consider enabling raw mode and applying a robust MIME parser when you need perfect fidelity.
- Inline images - the platform correlates
cid:references in HTML with attachments, which simplifies rendering. SendGrid passes files and HTML separately, you perform the correlation by matching the Content-ID in the headers of each attachment part.
Edge cases and robustness
- Forwarded chains and nested multiparts - the platform flattens nested structures into a consistent schema. With SendGrid, fields like
textandhtmlmight reflect only the top-level parts, so raw mode plus a MIME parser gives you more control. - Threading - both services preserve
Message-ID,In-Reply-To, andReferencesin headers. The platform exposes them as discrete fields, which can avoid mistakes from manual parsing. - Security - protect your webhook. The platform supports signing and token based auth, plus IP allowlists. Twilio publishes IP ranges for SendGrid inbound parse. Always verify the source and rotate credentials regularly.
Verdict - which is better for inbound email processing
If you are already deep in the Twilio ecosystem and comfortable working with multipart webhooks, SendGrid Inbound Parse is a solid choice that keeps everything in one vendor. It is especially fine for simple reply capture, lightweight routing, and pipelines where your team controls the domain and DNS.
If your requirements include instant address provisioning without DNS, structured JSON for every MIME part, retries with idempotency, and the option to poll via API, MailParse is the more streamlined path for inbound email processing. The developer experience leans toward fast integration - fewer moving parts in your code, less custom parsing, and reliable delivery patterns that are friendly to modern worker queues.
For broader planning across your stack, review the Email Infrastructure Checklist for SaaS Platforms to make sure your inbound pipeline pairs well with outbound deliverability, monitoring, and compliance.
FAQs
Can I use my own domain without changing MX records?
With SendGrid Inbound Parse, you must delegate MX for a subdomain you control. With MailParse, you can start with instant addresses on managed domains, then optionally bring your domain later if desired.
What is the best way to handle large attachments?
Respond quickly and move heavy work to a background queue. On the platform, leverage attachment metadata and checksums to validate storage. On SendGrid, stream multipart file parts to object storage, compute a hash, and avoid buffering full files in memory.
How do I verify the authenticity of inbound webhooks?
Enable webhook signing or tokens and restrict by IP ranges where available. Twilio publishes IP ranges for sendgrid inbound parse, and you can add a secret token to your webhook URL. The platform offers signing plus allowlisting options. Always log and audit verification failures.
What if I need the raw email for legal or compliance reasons?
SendGrid supports raw mode using send_raw=1, which posts the full RFC 822 message. The platform stores or returns the raw source on demand while still providing decoded JSON for everyday processing, so you get both convenience and fidelity.
How do I migrate from SendGrid Inbound Parse without downtime?
Run both pipelines in parallel. Keep SendGrid as the MX handler, forward to your new endpoint while also polling or receiving from the platform, and verify parity on a subset of mailboxes. Once payloads match and processing is stable, cut over gradually. For inspiration on workflows you can enable, see Top Email Parsing API Ideas for SaaS Platforms.