Email Authentication: MailParse vs SendGrid Inbound Parse

Compare MailParse and SendGrid Inbound Parse for Email Authentication. Features, performance, and developer experience.

Why email authentication should drive your inbound parsing choice

Email authentication is not only for outbound deliverability. On the inbound side, your application needs to know who actually sent a message and whether anything was altered in transit. That means parsing and validating SPF, DKIM, and DMARC, then exposing the results in a way that is easy to consume in code. If your inbound email parsing service handles authentication poorly, your app may accept spoofed or manipulated messages, misroute tickets, or create security exposures.

Strong email-authentication support turns every incoming message into a structured, signed event your platform can trust. In practice, that requires:

  • Validating SPF against the SMTP envelope, not just the From: header, and surfacing which identity passed or failed.
  • Verifying all DKIM signatures, not only the first one, and reporting per-signature results and selectors.
  • Evaluating DMARC alignment against the authenticated identifier and the visible From domain, with policy awareness.
  • Preserving the full Authentication-Results header and raw MIME so you can audit and re-check later.
  • Handling real-world edge cases like forwarded mail, multiple signatures, and volatile DNS.

If you are designing a SaaS feature that depends on trusted inbound mail, the way a platform implements these checks will determine your security posture and how much glue code you need to write. The sections below compare how a modern JSON-first service and Twilio SendGrid Inbound Parse approach authentication, where each is strong, and what it takes to ship production-grade validations.

Related reading for your stack: Email Infrastructure Checklist for SaaS Platforms and Top Inbound Email Processing Ideas for SaaS Platforms.

How MailParse Handles Email Authentication

MailParse (MP) validates SPF, DKIM, and DMARC on every inbound message and returns structured JSON that captures both the verdicts and the underlying evidence. The goal is to let your application make an informed decision without scraping headers or building an email-auth stack from scratch.

SPF validation

  • Checks SPF per RFC 7208 against the SMTP MAIL FROM identity, with a HELO fallback when the envelope sender is empty.
  • Captures verdicts like pass, fail, softfail, neutral, none, temperror, and permerror.
  • Includes the evaluated domain, connecting IP, scope, and the mechanism that produced the result.

DKIM verification

  • Validates every DKIM signature it finds, not just the first one.
  • Returns an array of signature objects with selector, domain, result, canon, and body hash status.
  • Handles large DNS keys, CNAME indirection, and multiple headers in canonicalization.

DMARC evaluation and alignment

  • Evaluates DMARC per RFC 7489, including alignment mode (relaxed or strict), organizational domain calculation, and subdomain policy.
  • Reports whether alignment passed via SPF or DKIM, and exposes policy metadata such as p, sp, and pct.
  • Surfaces the platform's DMARC decision alongside the underlying SPF and DKIM outcomes.

ARC and header preservation

  • Validates ARC chains when present and exposes the chain length and trust decision. This helps your app accept properly authenticated mail that traversed a forwarder or list.
  • Preserves the original Authentication-Results, Received, and all other headers in both structured form and raw MIME so you can audit later.

Webhook and polling payloads

By default, MP delivers a JSON payload to your webhook or via REST polling with a schema that includes:

{
  "id": "evt_01HX...",
  "received_at": "2026-04-24T15:02:12Z",
  "smtp": {
    "mail_from": "bounce@example.net",
    "helo": "mx.example.net",
    "remote_ip": "203.0.113.9"
  },
  "auth": {
    "spf": { "result": "pass", "domain": "example.net", "scope": "mfrom", "mechanism": "ip4", "ip": "203.0.113.9" },
    "dkim": [
      { "result": "pass", "domain": "example.org", "selector": "s1", "canon": "relaxed/relaxed" }
    ],
    "dmarc": {
      "result": "pass",
      "aligned_via": "dkim",
      "domain": "example.org",
      "policy": { "p": "quarantine", "sp": "none", "adkim": "r", "aspf": "r", "pct": 100 }
    },
    "arc": { "validated": true, "chain": 2 }
  },
  "headers": { "...": "..." },
  "raw": "RFC 5322 message bytes"
}

This structure avoids header scraping and encourages consistent handling of email authentication across all of your pipelines.

How SendGrid Inbound Parse Handles Email Authentication

Twilio SendGrid Inbound Parse receives mail at SendGrid MX records and forwards the message contents to your webhook. The service posts a multipart/form-data payload with convenience fields like from, to, subject, html, and text. For authentication, sendgrid's payload can include dkim, SPF, spam, spam_score, spam_report, sender_ip, and envelope. When the Post the raw, full message setting is enabled, the request also contains the full RFC message in an email field, and you can parse Authentication-Results yourself.

Important details for teams focused on email-authentication:

  • SPF and DKIM: The SPF and dkim fields provide basic pass or fail indicators. They are sufficient for simple checks, but do not enumerate multiple DKIM signatures with per-signature metadata.
  • DMARC: The webhook does not provide a native DMARC verdict or alignment details. You can compute DMARC by combining the visible From domain with SPF and DKIM outcomes taken from headers or the convenience fields, or by parsing the raw message.
  • ARC: There is no first-class ARC evaluation. If ARC matters for forwarded messages, you need to verify it from the raw headers using your own library.
  • Transport: The form-data payload is widely compatible, but increases the amount of parsing code you write for authentication use cases compared to JSON.
  • Setup: sendgrid-inbound-parse requires pointing your domain's MX to mx.sendgrid.net. If your inbound flow needs to live outside of the SendGrid ecosystem, that adds operational constraints.

In short, SendGrid Inbound Parse is reliable for receiving and forwarding email content, it exposes basic SPF and DKIM signals, and it offers raw MIME on demand. Teams that need DMARC and ARC decisions will implement those themselves. If you are already standardized on Twilio's stack and only need pass or fail flags, it remains a pragmatic choice.

Side-by-side authentication feature comparison

Feature MP SendGrid Inbound Parse
SPF result with evaluated domain and scope Yes, full RFC 7208 results with mechanism and scope Basic SPF field with pass or fail
HELO fallback when MAIL FROM is empty Yes, surfaced in payload Not explicitly surfaced
DKIM multi-signature reporting Yes, array of signatures with selectors and canonicalization Single dkim field, multiple signatures not enumerated
DMARC verdict and alignment Yes, alignment and policy metadata No native verdict, compute yourself from headers
ARC chain evaluation Yes, chain length and validity No built-in evaluation
Authentication-Results preservation Yes, structured and raw Raw header available if you enable full message posting
Raw MIME access Always available in payload Available when Post the raw, full message is enabled
Webhook transport JSON with typed authentication objects Multipart form-data
Webhook signing HMAC signature header for verification Optional request signing via Twilio security features
Forwarding resilience via ARC Yes, evaluates ARC to accept authenticated forwards Requires custom ARC verification

Code examples

MP webhook handler that enforces DMARC

The example below accepts a JSON payload, verifies the HMAC signature, then applies a policy that requires DMARC pass or an ARC-validated forward. Replace the secret and tune to your needs.

// Node.js + Express
const express = require("express");
const crypto = require("crypto");
const app = express();

app.use(express.json({ limit: "10mb" }));

function verifySignature(req, body, secret) {
  const sig = req.get("X-MP-Signature"); // base64 HMAC-SHA256
  const hmac = crypto.createHmac("sha256", secret).update(body).digest("base64");
  return crypto.timingSafeEqual(Buffer.from(sig || "", "base64"), Buffer.from(hmac, "base64"));
}

app.post("/webhooks/inbound", (req, res) => {
  const rawBody = JSON.stringify(req.body);
  if (!verifySignature(req, rawBody, process.env.MP_WEBHOOK_SECRET)) {
    return res.status(401).send("invalid signature");
  }

  const auth = req.body.auth || {};
  const dmarc = auth.dmarc || {};
  const arc = auth.arc || {};

  // Accept if DMARC passed or if ARC chain validated and SPF or DKIM passed upstream
  const dkimPassed = (auth.dkim || []).some(sig => sig.result === "pass");
  const spfPassed = (auth.spf && auth.spf.result === "pass");

  const accept =
    dmarc.result === "pass" ||
    (arc.validated === true && (dkimPassed || spfPassed));

  if (!accept) {
    // Quarantine or flag for manual review
    console.warn("Auth failure", { id: req.body.id, auth });
    return res.status(202).send("quarantined");
  }

  // Process the message
  // ...
  return res.status(200).send("ok");
});

app.listen(3000);

SendGrid Inbound Parse handler with DIY DMARC alignment

This example parses the form-data payload, reads the SPF and dkim fields, and evaluates a simplified DMARC alignment against the visible From domain. If you enable posting of the raw message, you can parse full headers from req.body.email for better fidelity.

// Node.js + Express with form-data parsing
const express = require("express");
const multer = require("multer");
const app = express();
const upload = multer();

function domainFromAddress(addr) {
  const match = /@([^>]+)>?$/.exec(addr || "");
  return match ? match[1].trim().toLowerCase() : "";
}

function relaxedAlign(child, parent) {
  // Very simplified org-domain check. Use a real PSL-based library in production.
  return child === parent || child.endsWith("." + parent);
}

app.post("/sendgrid/inbound", upload.any(), (req, res) => {
  // Typical fields: req.body.from, req.body.to, req.body.SPF, req.body.dkim, req.body.email
  const visibleFrom = (req.body.from || "").toString();
  const fromDomain = domainFromAddress(visibleFrom);

  const spfField = (req.body.SPF || "").toString().to

Ready to get started?

Start parsing inbound emails with MailParse today.

Get Started Free