Email Authentication for Platform Engineers | MailParse

Email Authentication guide for Platform Engineers. SPF, DKIM, and DMARC validation for verifying sender identity and preventing spoofing tailored for Engineers building internal platforms and developer tools with email capabilities.

Why Email Authentication Matters for Platform Engineers

Email authentication is not just a deliverability checkbox. For platform-engineers who own internal tooling and developer platforms, authentication is a trust boundary. Your systems receive messages that trigger workflows, open tickets, create CI jobs, or post to chat. Without robust SPF, DKIM, and DMARC validation, an attacker can spoof a supplier, a build bot, or a customer and trick your automation. If your platform ingests inbound mail via a parsing API or webhook, validation must be a first-class concern that is enforced before any business logic runs.

Modern platforms also operate in multi-tenant environments where a single ingress pipeline accepts messages addressed to many domains. That multiplies the complexity of email-authentication because DKIM alignment and DMARC policy differ per domain. If you use MailParse to receive and parse inbound email into JSON, you still need to attach rigorous sender validation before routing to tenants or triggering downstream jobs.

This guide distills how SPF, DKIM, and DMARC work, how to implement inbound validation at scale, and what pitfalls platform engineers should avoid when building email capabilities into internal platforms.

Email Authentication Fundamentals for Platform Engineers

SPF: Path-based validation

Sender Policy Framework verifies that the connecting IP is authorized to send mail on behalf of the envelope-from (Return-Path) domain. In an inbound pipeline, you must check SPF against the SMTP client IP and the RFC5321.MailFrom domain. Key notes:

  • SPF aligns with DMARC only when the domain in the visible From header matches the SPF-checked domain, either exactly or as a subdomain, depending on policy.
  • SPF outcomes: pass, fail, softfail, neutral, temperror, permerror. Treat temperror as transient, permerror as a policy decision.
  • DNS lookups can chain up to 10. Cache TXT records and handle "include:" mechanisms to avoid performance issues.

DKIM: Content-based validation

DomainKeys Identified Mail signs selected headers and the body with a domain-keyed signature. Inbound verification uses the DKIM-Signature header, reconstructs canonicalized headers and body, fetches the public key via DNS, and verifies the signature. Key notes:

  • Multiple signatures are common - pick the strongest aligned pass.
  • Canonicalization can be simple or relaxed. Be careful with whitespace and header folding.
  • Body length tag "l=" allows truncation. Verify within bounds.

DMARC: Policy and alignment

Domain-based Message Authentication, Reporting and Conformance builds on SPF and DKIM. DMARC checks the visible From domain against SPF and DKIM results, then applies the domain's policy: none, quarantine, or reject.

  • Alignment can be strict or relaxed. Relaxed allows subdomain alignment.
  • If either DKIM or SPF passes with alignment, DMARC can pass.
  • DMARC adds reporting (RUA, RUF). For multi-tenant platforms, route reports to an aggregate mailbox and parse for insights.

ARC: Authenticated Received Chain

If your platform forwards mail, ARC preserves upstream authentication results for downstream receivers. For purely inbound processing you usually do not need to sign with ARC, but you should parse ARC sets to inform anti-spoofing decisions when mail passes through trusted intermediaries.

Practical Implementation: Inbound Validation Pipeline

The high-level architecture most platform engineers implement looks like this:

  • Ingress: Receive raw MIME via SMTP or a provider. If you rely on MailParse webhooks, you will get structured JSON and access to raw headers and body.
  • Parsing: Normalize CRLF, parse headers and MIME parts, extract attachments and content types.
  • Authentication: Perform SPF, DKIM, and DMARC checks before business logic. Persist results.
  • Policy: Enforce per-tenant rules - for example, route only if DMARC aligned pass, quarantine on fail, allow list known partners.
  • Routing: Deliver to downstream services via events or HTTP callbacks.

Data model for authentication results

{
  "message_id": "abc123@example.com",
  "from": {"display": "Build Bot", "addr": "bot@ci.example.com", "domain": "ci.example.com"},
  "envelope": {"mail_from": "bounce@mailer.example.net", "rcpt_to": "hooks@ingress.yourapp.io"},
  "received_ip": "203.0.113.14",
  "spf": {"result": "pass", "domain": "mailer.example.net", "aligned": false},
  "dkim": [
    {"domain": "ci.example.com", "selector": "s1", "result": "pass", "aligned": true},
    {"domain": "mailer.example.net", "selector": "s2", "result": "pass", "aligned": false}
  ],
  "dmarc": {"domain": "ci.example.com", "policy": "quarantine", "alignment": {"spf": false, "dkim": true}, "result": "pass"},
  "arc": {"result": "none"},
  "verdict": "accept"
}

Execution order and caching

  • Perform SPF early because it requires the connecting IP. If your ingress provider supplies it in metadata, include it in the webhook payload.
  • DKIM verification requires the raw header and body. Keep the exact octet sequence. Normalize line endings to CRLF before hashing if required by your library.
  • Cache DNS TXT lookups for SPF and DKIM keys with short TTL honoring, use a shared resolver with UDP and TCP fallback, and guard against timeouts.
  • Apply DMARC alignment using the visible From domain and the best pass from SPF or DKIM.

Code pattern: Go with go-msgauth

// go.mod requires: github.com/emersion/go-msgauth, github.com/emersion/go-message
msg := rawMessageBytes // CRLF-preserved []byte
fromDomain := extractFromDomain(msg)
ip := net.ParseIP(clientIP)
mailFrom := envelopeFromDomain

spfRes, _ := msgauth.CheckSPF(ip, mailFrom)
// DKIM can return multiple results
dkimResSet, _ := msgauth.VerifyDKIM(bytes.NewReader(msg))
dmarcRes, _ := msgauth.CheckDMARC(fromDomain, spfRes, dkimResSet)

aligned := dmarcRes.Result == msgauth.DMARCResultPass
if !aligned {
  // Apply policy - quarantine or drop
}

Code pattern: Node.js

// libs: dkim-verify, spf-check2, dmarc-parse
const raw = Buffer.from(req.body.raw); // From webhook
const fromDomain = parseFromDomain(raw);
const spf = await spfCheck(req.body.received_ip, req.body.envelope.mail_from);
const dkim = await verifyDkim(raw);
const dmarc = dmarcParse(await dnsTxt(`_dmarc.${fromDomain}`));

const aligned = dmarcAlign(fromDomain, spf, dkim, dmarc);
if (!aligned) return res.status(202).json({verdict: "quarantine"});

Code pattern: Python

# libs: dkim, dmarc, pyspf
raw = get_raw_message_bytes()
ip = request_meta["received_ip"]
mail_from = envelope_mail_from
spf_res, spf_code = spf.check2(i=ip, s=mail_from, h=from_domain)

dkim_ok = dkim.verify(raw)
dmarc_record = dmarc.get_record(from_domain)
aligned = evaluate_dmarc(from_domain, spf_res, dkim_ok, dmarc_record)
if not aligned:
    quarantine(message_id)

Once you have deterministic results, tag messages with an internal "auth" label and store them alongside parsed content. If your ingestion comes via MailParse, persist the authentication fields together with the JSON to power audits and rule engines.

Tools and Libraries Platform Engineers Use

  • Go: github.com/emersion/go-msgauth for SPF, DKIM, DMARC. Pair with github.com/emersion/go-message for MIME parsing. Good for high-throughput services.
  • Node.js: dkim-verify, spf-check2, dmarc-parse. Use PostalMime or mailparser for MIME. Combine with clustering for concurrency.
  • Python: dkim, pyspf, dmarc packages. Use email.message for MIME or mail-parser for convenience.
  • Postfix/OpenDKIM/OpenDMARC: If running your own MTA, these daemons can annotate headers with Authentication-Results for downstream consumers.
  • Resolvers: Unbound or CoreDNS with DNS over TLS optional. Tune timeouts and enable TCP fallback for large DNS replies.

These libraries focus on correctness and standards compliance. When paired with an ingestion service like MailParse that produces raw headers and structured JSON, you can assemble a reliable, end-to-end email authentication pipeline without reinventing MIME handling.

For broader infrastructure guidance, see the Email Infrastructure Checklist for SaaS Platforms and the Email Deliverability Checklist for SaaS Platforms.

Common Mistakes Platform Engineers Make with Email Authentication

  • Trusting "From" without alignment checks: Always compute DMARC alignment between the From domain and SPF or DKIM results.
  • Discarding the raw message too early: DKIM verification requires the exact octet stream. Store or verify before any normalization beyond canonicalization.
  • Ignoring SPF temperror vs permerror: Treat temperror as transient and consider retry or soft accept with quarantine. Permerror is a policy call.
  • Not handling multiple DKIM signatures: Pick any aligned pass. Beware of mixed results where a third party passes but the author domain fails.
  • Forgetting IPv6 in SPF evaluation: Many senders publish AAAA records. Your policy engine should evaluate both IPv4 and IPv6.
  • DNS corner cases: Handle CNAME chains for selectors, TXT records longer than 255 bytes, and UDP truncation requiring TCP retry.
  • Failing open on DNS timeouts without logging: If you must fail open, tag the message so downstream systems know authentication is uncertain.
  • Applying one-size-fits-all policy: Tenants vary. Some accept quarantined messages for human review, others require strict reject for automation.
  • Skipping ARC in forwarder scenarios: If your platform forwards to other inboxes, implement ARC to preserve upstream results.

Advanced Patterns for Production-grade Email Processing

Multi-tenant policy enforcement

Store per-tenant policy objects that define thresholds and exceptions. Example:

{
  "tenant": "acme",
  "policy": {
    "require_dmarc_aligned": true,
    "quarantine_on_spf_temperror": true,
    "allowlist": ["github.com", "statuspage.io"],
    "forwarding_arc_required": false
  }
}

Enforce these policies inside a stateless microservice that receives parsed messages and authentication results from a queue. Queue messages include an idempotency key to prevent duplicate processing.

Webhook security and replay protection

  • Verify webhook signatures with HMAC over raw body, include timestamp and nonce.
  • Reject if timestamp is outside a short window, store nonces for a TTL to prevent replay.
  • If you poll via REST, use ETag or cursor-based pagination and fetch raw bytes only when needed for DKIM.

Queue-first design

Immediately enqueue the raw message and metadata, acknowledge the ingress, then perform SPF, DKIM, DMARC in workers. This isolates network spikes and DNS latency. Use a dead-letter queue for temperror cases you want to retry. Persist partial results with a state machine: received - spf_checked - dkim_checked - dmarc_evaluated - routed.

ARC in forwarders and bots

If your platform modifies or forwards emails, signing with ARC lets downstream receivers trust the chain. Keep modifications minimal to avoid breaking DKIM, or re-sign with your domain and preserve Authentication-Results headers.

Policy augmentation: MTA-STS and TLSRPT

While not directly part of SPF, DKIM, and DMARC, enforcing MTA-STS for outbound relays and collecting TLSRPT improves your overall security posture. For inbound, require TLS on SMTP sessions where possible and record cipher details for audits.

Actionable alerts and reporting

  • Aggregate DMARC failures per domain and source ASN. Alert when a new source begins sending to your platform with low pass rates.
  • Create dashboards that show aligned pass rate by tenant, top failing domains, and DNS error trends.
  • Feed RUA data into a data warehouse for anomaly detection. Many libraries can parse RUA XML into structured rows.

If you are exploring more advanced inbound workflows, see Top Inbound Email Processing Ideas for SaaS Platforms for ways to turn authenticated messages into product features.

Conclusion

Email authentication is a core security layer for platforms that react to inbound mail. SPF confirms path, DKIM proves content integrity, and DMARC enforces alignment with sender identity. Implement them early in your pipeline, cache DNS efficiently, and apply per-tenant policies to match risk tolerance. With a robust ingestion and parsing foundation like MailParse, you can attach reliable SPF, DKIM, and DMARC validation to every message and protect your platform's automations from spoofing.

FAQ

Do I need to verify both SPF and DKIM, or is one enough?

Verify both. DMARC passes if either SPF or DKIM passes with alignment, but as an inbound platform you should compute both to maximize signal. Many legitimate senders rely on DKIM but fail SPF when messages are forwarded. Others may have weak DKIM but correct SPF. Evaluating both improves confidence and routing accuracy.

How do I handle messages without a DKIM signature?

Run SPF and DMARC. DMARC can still pass via SPF alignment. Apply tenant policy for unsigned mail - for example, route to a manual review queue or quarantine if the tenant requires strict enforcement. If the sending domain publishes p=reject and there is no aligned pass, treat as fail.

What about internal systems that email our platform from non-routable IPs?

Allowlist internal subnets and domains in your policy engine. For internal senders, you can also sign with your own DKIM key and set a local policy that requires a DKIM pass from your domain. Keep these exceptions scoped to known networks and authenticated SMTP sessions.

Does using an inbound parsing service replace the need for SPF, DKIM, and DMARC checks?

No. Parsing services focus on reliable delivery and MIME normalization. You still need to validate sender identity. Services like MailParse provide raw headers and bodies via webhook or polling, which enables you to perform full SPF, DKIM, and DMARC checks within your trust boundary.

Should I reject messages on temperror results?

Temperror indicates a transient DNS or network problem. In most platforms, quarantine or defer processing, then retry. Use a circuit breaker so that widespread DNS issues do not overload your workers. Reserve hard rejects for explicit DMARC fails or policy decisions.

Ready to get started?

Start parsing inbound emails with MailParse today.

Get Started Free