Email Infrastructure: MailParse vs Mailgun Inbound Routing

Compare MailParse and Mailgun Inbound Routing for Email Infrastructure. Features, performance, and developer experience.

Introduction: Why Email Infrastructure Matters for Inbound Parsing

Inbound email is a core workflow for modern SaaS, support platforms, and developer tools. Support ticket ingestion, replies to notification emails, billing exceptions, and automated workflows all depend on reliable, scalable email-infrastructure. When choosing an email parsing service, the question is not just about extracting subject, body, and attachments. It is about how the system terminates SMTP, handles MX routing, isolates tenants, validates signatures, retries webhooks, preserves raw MIME, and exposes a predictable API for downstream applications. Solid email infrastructure turns unpredictable SMTP traffic into dependable events.

This article compares two approaches to building scalable email processing pipelines - one centered around instant inbox provisioning, structured JSON, and resilient webhook delivery, and the other centered around mailgun-inbound-routing with domain routes and multipart webhook payloads. We will focus on technical depth: MX records, SMTP relays, MIME parsing details, signature verification, idempotency, delivery guarantees, and operational behavior under load.

For a broader operational checklist on standing up email in production, see the Email Infrastructure Checklist for SaaS Platforms. If you are mapping inbound email use cases to product features, explore Top Inbound Email Processing Ideas for SaaS Platforms.

How MailParse Handles Email Infrastructure

At its core, MailParse provides instant email addresses, SMTP ingress, MIME-to-JSON parsing, and delivery through webhooks or REST polling. The inbound pipeline is designed for developer ergonomics and fault tolerance across each step of the journey.

MX records and SMTP ingress

  • Shared or custom domains - create programmatic inboxes on shared domains, or bring your own domain and point MX records to the provider's SMTP edge. Catch-all and per-alias routing are supported for multi-tenant SaaS flows.
  • TLS enforcement - inbound connections are accepted over TLS whenever available to protect data-in-transit.
  • Anti-abuse controls - recipient validation and rate shaping mitigate floods and misrouted traffic before parsing.

MIME parsing to structured JSON

  • Full MIME normalization - the service decodes charsets, normalizes HTML and plain text, and extracts attachments with content-type and size metadata.
  • Preserved raw MIME - a message reference to the raw MIME is included for audit, reprocessing, and compliance.
  • Edge case handling - DSNs, winmail.dat (TNEF), S/MIME-signed content, and nested multipart structures are parsed deterministically so downstream systems do not have to guess.

Webhook delivery and REST polling

  • Webhook format - JSON with a stable schema. Each event includes headers, envelope, text and HTML bodies, attachments metadata, and a pointer to raw MIME for on-demand retrieval.
  • Reliability - at-least-once delivery with exponential backoff, jitter, and dead-letter retention. Replay is supported by message ID through REST.
  • Security - HMAC signatures on every webhook using a per-project secret. Includes timestamp headers for replay protection and a unique event ID for idempotency.
  • Polling - REST endpoints expose messages by inbox, status, or time range, useful for backfills or when webhooks are disabled during maintenance windows.

Example JSON schema excerpt

{
  "id": "msg_01hv2h6r2t3r9xw",
  "inbox": "support+1234@yourapp.example",
  "received_at": "2026-04-25T12:43:21Z",
  "envelope": {
    "from": "alice@example.com",
    "to": ["support+1234@yourapp.example"]
  },
  "headers": {
    "message-id": "<abc123@example.com>",
    "subject": "Re: Order 4567"
  },
  "body": {
    "text": "Plain-text body...",
    "html": "<p>HTML body</p>"
  },
  "attachments": [
    {
      "id": "att_7q3",
      "filename": "invoice.pdf",
      "content_type": "application/pdf",
      "size": 245671
    }
  ],
  "raw_mime_url": "https://api.provider.example/messages/msg_01hv2.../mime",
  "signature": {
    "version": "v1",
    "timestamp": "1714046400",
    "hash": "hmac-sha256-hex"
  }
}

How Mailgun Inbound Routing Handles Email Infrastructure

Mailgun's inbound routing is built around domain routes. You configure routes by domain, recipient pattern, or priority and then invoke actions like forward to a webhook, store, or stop. The service terminates SMTP on Mailgun's global edge and delivers events to your application as multipart form data.

MX records and domain routes

  • MX configuration - point your domain's MX to Mailgun's SMTP to enable inbound. Per-domain route tables define how recipients are handled.
  • Recipient-based routing - define actions for specific recipients, catch-all addresses, or wildcard patterns. Priority determines the first matching route.

Webhook payload format and MIME access

  • Multipart form-data - inbound events are posted as multipart HTTP requests. Fields include sender, recipient, subject, body-plain, body-html, and stripped variants.
  • Attachments - sent as file parts. You can also fetch the full raw MIME via a message URL if configured to store it.
  • Security - Mailgun includes timestamp, token, and signature fields. Verification uses HMAC with your API key over the concatenation of timestamp and token.

Strengths and limitations

  • Strengths - mature SMTP edge, well-documented signature scheme, flexible routing, and optional storage.
  • Limitations - multipart form-data can complicate parsing across languages, and per-community reports cite inconsistent webhook delivery during spikes. Cost can rise quickly at high inbound volumes due to per-message and storage pricing.

Side-by-Side Comparison of Email Infrastructure Features

Capability MailParse Mailgun Inbound Routing
MX setup for custom domains Bring-your-own domain with MX to provider's SMTP. Catch-all or per-alias inboxes. MX to Mailgun with domain routes, recipient patterns, and priorities.
Instant inbox provisioning API to create programmatic inboxes on shared or custom domains in real time. Routes per domain, not per ephemeral inbox. Aliases via recipient patterns.
Webhook format JSON with stable schema, includes raw_mime_url, attachments metadata. Multipart form-data with text fields and file parts, optional message URL.
Signature verification HMAC headers with timestamp and event ID for idempotency. HMAC over timestamp+token fields with API key.
Retries and delivery guarantees At-least-once with exponential backoff, jitter, and replay via REST. Retries supported, but delivery consistency can vary during traffic spikes.
MIME fidelity Normalized JSON plus preserved raw MIME for audit and reprocessing. Multipart body fields, raw MIME available if stored.
Attachments Attachment metadata in JSON with streaming fetch APIs. Attachments as webhook file parts, optional stored retrieval.
Idempotency and de-duplication Event ID in headers and payload. Recommended to store processed IDs. Use Mailgun signature fields and message-id to implement app-level idempotency.
Operational cost at scale Predictable usage-based pricing for inbound parsing. Per-message and storage costs can become expensive at scale.

Code Examples: Developer Experience for Email-Infrastructure

Webhook receiver and signature verification using JSON

Example in Node.js with Express. This expects JSON webhooks, validates HMAC signatures, and handles idempotency via the event ID.

import crypto from "crypto";
import express from "express";

const app = express();
app.use(express.json({ limit: "25mb" }));

const SIGNING_SECRET = process.env.SIGNING_SECRET;

function verifySignature(req) {
  const timestamp = req.header("X-Timestamp");
  const signature = req.header("X-Signature");
  const body = JSON.stringify(req.body);
  const data = `${timestamp}.${body}`;
  const expected = crypto.createHmac("sha256", SIGNING_SECRET).update(data).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

const processed = new Set(); // naive idempotency store

app.post("/webhooks/email", (req, res) => {
  if (!verifySignature(req)) return res.status(401).send("invalid signature");

  const eventId = req.header("X-Event-Id");
  if (processed.has(eventId)) return res.status(200).send("duplicate");
  processed.add(eventId);

  const msg = req.body;
  // Your business logic: create ticket, map to tenant, store attachments, etc.
  console.log("Inbound message:", {
    from: msg.envelope.from,
    to: msg.envelope.to,
    subject: msg.headers.subject
  });

  res.status(200).send("ok");
});

app.listen(3000, () => console.log("listening on 3000"));

REST polling for backfills

# Fetch messages for a specific inbox over a window
curl -H "Authorization: Bearer $API_TOKEN" \
  "https://api.provider.example/v1/messages?inbox=support%2B1234@yourapp.example&since=2026-04-01T00:00:00Z"

Mailgun inbound route receiver with signature verification

Mailgun posts multipart form-data. This example uses Express with Multer to parse the request and validates the signature per mailgun's docs.

import crypto from "crypto";
import express from "express";
import multer from "multer";

const app = express();
const upload = multer(); // parses multipart/form-data
const API_KEY = process.env.MAILGUN_API_KEY;

function verifyMailgun(req) {
  const timestamp = req.body.timestamp;
  const token = req.body.token;
  const signature = req.body.signature;
  const data = timestamp + token;
  const expected = crypto.createHmac("sha256", API_KEY).update(data).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

app.post("/mailgun/inbound", upload.any(), (req, res) => {
  if (!verifyMailgun(req)) return res.status(401).send("invalid signature");

  const sender = req.body.sender;
  const recipient = req.body.recipient;
  const subject = req.body.subject;
  const text = req.body["body-plain"];
  const html = req.body["body-html"];

  // Attachments arrive as files
  const files = req.files || [];

  console.log("Mailgun inbound:", { sender, recipient, subject, attachments: files.length });

  // Optional: fetch full MIME via message-url if provided and stored
  // const mimeUrl = req.body["message-url"];

  res.status(200).send("ok");
});

app.listen(3001, () => console.log("listening on 3001"));

Performance and Reliability in Real-World Email-Infrastructure

Latency and throughput

For production pipelines, you want stable end-to-end latency from SMTP receipt to webhook delivery. JSON webhooks are typically lighter than multipart form-data, which can reduce overhead in your application stack. Both approaches can process high throughput, but the shape of your traffic matters. Bursty traffic with large attachments benefits from streaming attachment retrieval rather than posting files inline to webhooks.

Retry, backoff, and dead-lettering

  • JSON event pipelines often include at-least-once delivery semantics, exponential backoff with jitter, and selective replay by message ID. This helps you recover from temporary downstream outages without losing events.
  • mailgun-inbound-routing supports retries, but user reports sometimes note inconsistent webhook delivery under extreme spikes. Mitigation includes storing raw MIME on their side and polling, or buffering in a durable queue before your main app.

Edge cases: DSNs, malformed MIME, and encodings

  • Delivery Status Notifications - DSNs and bounce reports use multipart/report with message/delivery-status. Structured JSON that preserves both top-level headers and the embedded report is easier to consume than many multipart fields.
  • Malformed MIME and charset issues - robust parsers normalize common mistakes like missing boundaries or wrong charsets, and expose a raw MIME fallback. This is essential for long-tail senders and automated systems.
  • TNEF and calendar invites - winmail.dat and calendar parts need special handling to extract attachments and ICS data without data loss.

Security and compliance

  • Webhook signature verification - always verify HMAC signatures with timestamp checks to prevent replay. Prefer signing the full request body, not a subset of fields.
  • Idempotency - store processed event IDs and message-ids to avoid duplicate side effects during retries.
  • Least privilege - restrict webhook endpoints by IP or token, and segregate secrets per environment. Avoid logging raw MIME for PII safety unless redacted.

For deeper operational guidance on keeping pipelines healthy and trustworthy, see the Email Deliverability Checklist for SaaS Platforms.

Verdict: Which Is Better for Email Infrastructure?

If your team prioritizes JSON-first webhooks, instant inbox provisioning, and a strong focus on predictable delivery with replay and idempotency baked in, MailParse will likely feel more natural for building email-infrastructure. It simplifies inbound parsing, keeps MIME accessible when you need it, and makes operational controls like backoff, signatures, and polling straightforward.

If you already rely on mailgun's ecosystem, prefer domain route patterns, and are comfortable handling multipart form-data, Mailgun Inbound Routing delivers a mature inbound path. Be mindful of scaling costs and consider storing raw MIME on their side for resilient recovery when webhook delivery is inconsistent.

Teams that value streamlined developer experience and steady costs at scale tend to favor MailParse for inbound-heavy SaaS and customer support workflows, while Mailgun's routing can be a solid fit for organizations embedded in their sending stack and tooling.

FAQ

Do I need to change MX records to ingest inbound email?

Yes for custom domains. Point your domain's MX to the provider's SMTP edge so mail destined for your domain flows into the parsing pipeline. For quick prototyping or per-tenant inboxes, shared domains with programmatic aliases let you ingest mail without DNS changes.

JSON webhooks or multipart form-data - which is better?

JSON webhooks are easier to consume across languages and frameworks, simplify signature verification, and reduce parsing edge cases. Multipart form-data can be convenient for inline attachments but tends to increase parsing complexity and memory usage under load.

How do I implement idempotency for inbound emails?

Store a combination of the provider's event ID and the RFC message-id. When a webhook arrives, check if you have already processed that composite key. Respond 200 OK if it is a duplicate. This approach protects against retries and network glitches.

What is the recommended approach for large attachments?

Avoid pushing large binary attachments in the webhook body. Prefer metadata in the event and a signed URL to fetch the object on demand. Stream the download to storage to keep memory usage bounded.

Can I run both providers in parallel for migration?

Yes. Use dual MX or phased routing with subdomains. For example, route inbound@yourapp.example to your new stack while legacy@yourapp.example remains on the old path. Validate parity by comparing raw MIME, derived JSON, and downstream side effects before cutover.

Ready to get started?

Start parsing inbound emails with MailParse today.

Get Started Free