---
title: "Email Deliverability: SPF, DKIM, DMARC"
slug: "email-deliverability"
category: "backend"
tags: ["email", "dns", "deliverability", "security", "dmarc"]
status: "stable"
last_updated: 2026-06-16
summary: "Authenticate transactional mail with SPF, DKIM, and DMARC on a dedicated sending subdomain so it lands in the inbox, not spam."
related: ["[[ops/namecheap-dns]]", "[[ops/cloudflare-dns]]", "[[backend/auth-sessions]]", "[[ops/secrets-and-env]]", "[[backend/webhooks]]", "[[howto/launch-a-new-site]]"]
---

## Overview

Publish SPF, DKIM, and DMARC DNS records that align with your From domain before you send a single transactional email; mailbox providers route unauthenticated mail to spam regardless of content. This page is the house standard for any provider (Resend, Postmark, AWS SES). Each provider's dashboard shows the exact record values to copy; the rules below tell you which records, where they go, and how to verify them. Add the records at your DNS host: see [[ops/cloudflare-dns]] and [[ops/namecheap-dns]].

## Send from a dedicated subdomain, not the root domain

Use a subdomain like `mail.example.com` or `send.example.com` as the sending identity. This isolates sending reputation from your root domain, so a spam complaint against marketing mail does not poison the root domain that serves your site and corporate email. Verify the subdomain as the identity in your provider; the From header becomes `noreply@mail.example.com`.

## Publish exactly one SPF record on the sending domain

SPF is a single TXT record on the sending domain that authorizes which servers may send for it. Publish one and only one SPF record per domain; multiple `v=spf1` records are a permanent error and SPF fails outright ([dmarc.org](https://dmarc.org/wiki/FAQ)).

```dns
mail.example.com.  TXT  "v=spf1 include:amazonses.com ~all"
```

Use the provider's `include` mechanism (`include:amazonses.com` for AWS SES, the value Resend or Postmark shows you). `~all` is softfail; `-all` is hardfail. Most providers also have you add an MX record on the sending subdomain so bounce and complaint feedback can be processed ([Resend](https://resend.com/docs/dashboard/domains/introduction)).

## Publish the provider's DKIM keys and confirm they verify

DKIM signs each message with a private key the provider holds; receivers fetch the matching public key from DNS. Add the provider-issued records exactly as shown, then confirm the provider reports them verified. AWS SES Easy DKIM issues three CNAME records ([AWS SES docs](https://docs.aws.amazon.com/ses/latest/dg/send-email-authentication-dkim-easy.html)); Postmark issues a TXT record ([Postmark](https://postmarkapp.com/support/article/1091-how-do-i-set-up-dkim-for-postmark)).

```dns
xxxx._domainkey.mail.example.com.  CNAME  xxxx.dkim.amazonses.com.
```

Verification can take up to 48 to 72 hours to propagate. Do not send production mail until DKIM shows verified, or messages go unsigned.

## Publish a `_dmarc` TXT record and raise the policy over time

DMARC tells receivers what to do when SPF and DKIM fail, and where to send reports. Put a TXT record at `_dmarc.<domain>`:

```dns
_dmarc.mail.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
```

Start at `p=none` to collect aggregate reports (`rua=`) without affecting delivery. Read the reports, confirm your real mail passes, then raise the policy as confidence grows: `none -> quarantine -> reject` ([dmarc.org](https://dmarc.org/overview/)). Only `reject` actually stops spoofing. The alignment tags `adkim` and `aspf` default to relaxed (`r`) when omitted; prefer that default. Strict alignment (`adkim=s; aspf=s`) requires an exact domain match and breaks SPF alignment when your Return-Path is on a subdomain, as it typically is with third-party providers.

## Make DKIM and SPF align with the From domain

DMARC passes only when an authenticated identity aligns with the domain in the From header. In relaxed alignment mode (the default), a subdomain match counts: `mail.example.com` aligns with `example.com`. In strict mode, the domains must be identical. DKIM aligns when the signing `d=` domain matches (or, in relaxed mode, is a subdomain of) the From domain. SPF aligns when the Return-Path (MAIL FROM) domain matches the From domain under the same rules, which is why providers offer a custom Return-Path or custom MAIL FROM subdomain ([Postmark](https://postmarkapp.com/support/article/910-how-do-i-add-a-custom-return-path)). Because most providers route bounces through a subdomain like `pm-bounces.example.com`, strict SPF alignment (`aspf=s`) will fail; keep the default relaxed mode. The common failure is transactional mail landing in spam because DKIM and DMARC are unset, or because SPF passes on the provider's bounce domain but does not align with your From domain under the configured mode, so DMARC fails.

## Warm up a new domain gradually

A brand-new sending domain has no reputation. Ramp volume over days to weeks rather than blasting your full list on day one; sudden volume from an unknown domain looks like a compromised account and trips spam filters. Send to engaged recipients first and watch bounce and complaint rates.

## Related

- [[ops/cloudflare-dns]] and [[ops/namecheap-dns]]: where to add these TXT, CNAME, and MX records.
- [[ops/secrets-and-env]]: store provider API keys outside source control.
- [[backend/webhooks]]: handle provider bounce and complaint webhooks.
- [[backend/auth-sessions]]: transactional email backs password reset and magic-link flows.
- [[howto/launch-a-new-site]]: deliverability setup as part of launch.
