Inbound Email Processing: MailParse vs CloudMailin

Compare MailParse and CloudMailin for Inbound Email Processing. Features, performance, and developer experience.

Why Inbound Email Processing Matters

Inbound email processing is the foundation for product feedback loops, ticketing workflows, approvals, and automated data capture. If your application needs to receive, route, and process inbound emails via API, your choice of platform affects more than just delivery. It determines how fast you can ship, how resilient your system is under edge cases, and how cleanly you can transform MIME into actionable JSON.

Teams evaluating cloud-based inbound solutions often compare developer experience, payload structure, routing flexibility, retries, and support for large or unusual email formats. Getting these details right reduces glue code, prevents duplicate processing, and keeps customer workflows steady. If you are architecting email for a SaaS product, consider pairing this guide with the Email Infrastructure Checklist for SaaS Platforms and workflow ideas in Top Inbound Email Processing Ideas for SaaS Platforms.

How MailParse Handles Inbound Email Processing

The platform focuses on giving developers instant addresses, consistent JSON, and predictable delivery semantics. You can provision a unique email address per user, team, or workflow, receive inbound events via webhook, or poll via REST if your environment restricts inbound traffic. Each message is parsed from raw MIME to structured fields so your code works with normalized JSON rather than ad hoc header parsing.

Address provisioning and routing

  • Instant addresses: create per-user or per-resource addresses via API, or use plus-addressing to multiplex inbound email to a single route.
  • Flexible routing: route by full address, local part, tag, subdomain, or wildcard patterns to different webhooks or queues.
  • Custom domains: point MX records to the service and keep addresses on your brand domain.

Webhook delivery and JSON shape

Inbound events post to your HTTPS endpoint. The payload contains canonicalized fields and MIME-parsed parts, including inline and attached files with content metadata. An idempotency key allows safe retries and deduplication.

{
  "event_id": "evt_01J1Y0Z9QK3B8K3T8KJ4H3",
  "received_at": "2026-04-23T11:22:06Z",
  "envelope": {
    "from": "alice@example.com",
    "to": ["support@product.example"],
    "rcpt_to": ["support+us-east@product.example"]
  },
  "headers": {
    "message_id": "<CA+12345@example.com>",
    "subject": "Bug report",
    "date": "Wed, 23 Apr 2026 11:21:59 +0000",
    "dkim": "pass",
    "spf": "pass"
  },
  "parts": {
    "text": "Hi team,\nThe export button is timing out.\n",
    "html": "<p>Hi team,</p><p>The export button is timing out.</p>"
  },
  "attachments": [
    {
      "filename": "screenshot.png",
      "content_type": "image/png",
      "size": 482103,
      "sha256": "d970...f34a",
      "inline": false,
      "download_url": "https://files.api.example/att/att_01J1...Z"
    }
  ],
  "security": {
    "signature": {
      "algorithm": "HMAC-SHA256",
      "header": "X-Signature",
      "timestamp_header": "X-Signature-Timestamp"
    }
  }
}

Events include normalized "dkim" and "spf" results when available, plus a stable "event_id" for deduplication. Attachments are available as download URLs to keep webhook payloads small, with expiration and single-use options for security.

Verification, retries, and polling

  • Signature verification: compute HMAC-SHA256 over the request body plus a timestamp, compare with the X-Signature header, and reject if the timestamp is outside your tolerance window.
  • Retry policy: exponential backoff with jitter on non-2xx responses, up to a bounded maximum. The same "event_id" is reused on retry so you can dedupe safely.
  • REST polling: if webhooks are not feasible, poll a per-project inbox via REST using a cursor. Mark events as acknowledged after processing.

How CloudMailin Handles Inbound Email Processing

CloudMailin is a cloud-based inbound email service that receives mail on your behalf and posts it to an HTTP endpoint. You can configure routes per domain or address, then choose raw or parsed delivery modes.

Routing and address options

  • Use CloudMailin-provided addresses for quick start, or set MX on your domain to route production traffic.
  • Define routes by address or pattern so different recipients go to different endpoints. Plus-addressing rules and catch-all patterns are supported in typical setups.
  • Deliver to a single endpoint per route or split based on recipient values.

Payload formats and attachments

  • Parsed JSON or multipart form posts are available. In parsed mode, you get headers, plain text, HTML, and attachments.
  • Attachments can arrive as multipart file uploads or links depending on configuration, which keeps webhook payloads manageable for large files.
  • Raw mode forwards the RFC 822 message to your endpoint so you can run custom MIME logic.

Verification and retries

  • Request signing is available via an HMAC signature header. Verify the signature and timestamp on receipt to prevent spoofing.
  • Automatic retries occur on non-2xx responses. Ensure handlers are idempotent to avoid duplicates when a retry overlaps processing.

Side-by-Side Comparison of Inbound Email Processing Features

Capability MailParse CloudMailin
Address provisioning speed Instant address creation via API, plus-addressing and wildcard routing Dashboard or API driven, supports routes per address or domain
Delivery modes Webhook and REST polling for inbound events Webhook delivery, raw or parsed mode
JSON normalization Canonicalized keys, consistent attachment schema Parsed JSON or multipart with files. Raw available
Attachment handling Download URLs with short-lived tokens, size and hash metadata Multipart file uploads or links depending on configuration
Security and signing HMAC signature with timestamp headers, replay protection guidance HMAC signature header and verification best practices
Retries and idempotency Exponential backoff with event_id for dedupe Retries on non-2xx responses, build your own dedupe key
Routing rules Recipient, tag, and subdomain routing mapped to different webhooks Routes by address or pattern to endpoints per configuration
Ecosystem integrations Modern webhook-first approach, code samples and SDKs Smaller ecosystem, lean integration set
Edge-case MIME handling Focus on charset quirks, inline images, calendar invites, and S/MIME passthrough Parsed and raw support. Complex cases often handled in user code
Operational options REST polling for restricted networks Webhook centric

Code Examples: Developer Experience on Both Platforms

Example: Webhook handler for MailParse

This Node.js example verifies the HMAC signature, deduplicates by event_id, and processes attachments. The same logic works in any framework that can read the raw request body.

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

const app = express();

// Capture raw body for signature verification
app.use(express.raw({ type: "*/*", limit: "25mb" }));

// In-memory dedupe set for demo only. Use Redis or your DB in production.
const seen = new Set();

function verifySignature(rawBody, signature, timestamp, secret) {
  const hmac = crypto.createHmac("sha256", secret);
  hmac.update(timestamp + "." + rawBody);
  const expected = "sha256=" + hmac.digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

app.post("/inbound", (req, res) => {
  const sig = req.header("X-Signature");
  const ts = req.header("X-Signature-Timestamp");
  const secret = process.env.SIGNING_SECRET;

  if (!sig || !ts || !verifySignature(req.body, sig, ts, secret)) {
    return res.status(401).send("invalid signature");
  }

  const payload = JSON.parse(req.body.toString("utf8"));
  if (seen.has(payload.event_id)) {
    return res.status(200).send("duplicate ignored");
  }
  seen.add(payload.event_id);

  // Basic routing by recipient
  const rcpt = payload.envelope.rcpt_to[0] || "";
  if (rcpt.includes("+billing")) {
    // handle billing mailbox
  } else if (rcpt.includes("+support")) {
    // handle support mailbox
  }

  // Process attachments by URL
  for (const att of payload.attachments || []) {
    console.log("download attachment", att.filename, att.download_url);
    // fetch and store securely
  }

  // Persist message, then acknowledge
  res.status(200).send("ok");
});

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

Example: Webhook handler for CloudMailin

This example receives a parsed POST, verifies the CloudMailin signature header, and handles both text and attachment parts. Adapt the header names to your account's signing configuration.

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

const app = express();
app.use(express.raw({ type: "*/*", limit: "25mb" }));

function verifyCloudMailinSignature(rawBody, signature, secret) {
  // CloudMailin provides an HMAC signature header. Consult their docs for exact payload.
  const hmac = crypto.createHmac("sha256", secret);
  hmac.update(rawBody);
  const expected = hmac.digest("hex");
  try {
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  } catch {
    return false;
  }
}

app.post("/cm-inbound", (req, res) => {
  const sig = req.header("X-CloudMailin-Signature");
  if (!sig || !verifyCloudMailinSignature(req.body, sig, process.env.CM_SECRET)) {
    return res.status(401).send("invalid signature");
  }

  const evt = JSON.parse(req.body.toString("utf8"));

  // evt.headers.subject, evt.plain, evt.html, evt.attachments
  if (evt.plain && evt.plain.includes("unsubscribe")) {
    // put into compliance queue
  }

  for (const file of evt.attachments || []) {
    // file may be a multipart part or a link depending on configuration
    console.log("attachment", file.filename, file.size);
  }

  res.status(204).end();
});

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

Example: Polling API consumer

When inbound firewalls block webhooks, consume events via REST with cursor based pagination. Acknowledge each event once processed.

# 1) Fetch a page of events
curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://api.example.com/v1/inbound/events?cursor=next&limit=50" \
  | jq '.events[] | {id: .event_id, subject: .headers.subject}'

# 2) Ack events you have persisted
curl -X POST -sS -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ack_ids":["evt_01J1Y0Z9QK3B8K3T8KJ4H3","evt_01J1Y0Z9QK3B8K3T8KJ4H4"]}' \
  "https://api.example.com/v1/inbound/ack"

Performance and Reliability in Real-World Inbound Email Processing

Handling large attachments and timeouts

For multi-megabyte attachments, push links instead of inlining base64 content. This keeps webhook bodies small and lowers the risk of 413 Request Entity Too Large. Both platforms support delivering links or multipart file uploads. Ensure your HTTP server allows sufficient body size limits and timeouts during spikes.

Dealing with duplicate delivery

Retries are an operational reality. Build strict idempotency into your application. Use the event identifier from the payload if provided, or derive a stable key from headers like Message-ID plus recipient. Store processed keys in a durable cache and short-circuit duplicates at the edge of your handler.

MIME edge cases

  • Charset quirks: normalize to UTF-8 where safe, but preserve original bytes for forensic needs.
  • Inline images and content-id: replace cid: references with attachment URLs when rendering or indexing.
  • Calendar invites: extract ICS attachments and expose structured fields if your workflow needs scheduling.
  • S/MIME and PGP: treat encrypted parts as opaque. Persist securely and let downstream systems decrypt where appropriate.

Security and abuse prevention

  • Verify signatures and enforce a timestamp window to prevent replay.
  • Rate limit by sender domain or route. For public addresses, apply per-IP limits and graylisting when feasible.
  • Inspect SPF, DKIM, and DMARC results for risk scoring. Route suspicious traffic to a quarantine queue.

Operational playbooks

  • Use dead-letter queues for persistent failures. Keep raw MIME references for replay.
  • Emit metrics for 2xx rate, retry depth, parse errors, and average payload size. Alert on anomalies.
  • Document fallback paths. For example, switch a route from webhook to polling if egress is restricted during an incident.

If you also send outbound messages, make sure your inbound stack aligns with your compliance and deliverability strategy. Cross check DNS, authentication, and rate limits using the Email Deliverability Checklist for SaaS Platforms.

Verdict: Which Is Better for Inbound Email Processing?

Both services deliver reliable, cloud-based inbound-email-processing with sane defaults. CloudMailin is a straightforward option if you prefer a single webhook centric flow, support both raw and parsed modes, and are comfortable implementing more custom logic for deduplication and MIME edge cases in your application code.

If you value standardized JSON across diverse MIME inputs, need both webhooks and REST polling, want instant address creation at scale, and prefer attachment links that reduce payload bloat, then MailParse fits those requirements well. The smaller integration ecosystem on CloudMailin can mean more build time for ancillary tasks like storage offloading, idempotency, and advanced routing. Choose based on your integration surface, network constraints, and how much parsing work you want the platform to absorb.

FAQ

How do I route inbound emails to different microservices?

Use recipient based routing. Set unique addresses per workflow or apply plus-addressing to a shared mailbox, then configure routes that post to different endpoints per recipient pattern. Include a routing key in the webhook payload and keep handler logic small and composable.

What is the safest way to process large attachments?

Prefer signed download links over inline multipart uploads. Fetch attachments asynchronously, scan files if required, and enforce per-file size limits. Store content with checksums so you can detect duplicates or partial uploads.

How can I prevent duplicate processing during retries?

Deduplicate using a stable event key. If the payload includes an event identifier, store it in a persistent cache or database. If not, derive a key from Message-ID plus recipient plus size hash. Make handlers idempotent by checking this key before processing.

Do I need raw MIME access?

Keep a reference to the raw message for troubleshooting, legal requirements, or when your workflow needs low level MIME details. Use normalized JSON for everyday logic and fall back to raw only on demand.

What checklist should I follow before moving inbound to production?

Verify DNS and MX, signature verification, retries and timeouts, large body limits, and idempotent processing. Test edge cases like multiple recipients, non-UTF-8 charsets, and calendar invites. Use the Email Infrastructure Checklist for Customer Support Teams if your primary use case is shared inboxes and ticketing.

Ready to get started?

Start parsing inbound emails with MailParse today.

Get Started Free