DMARC Engine
Home/Blog/How to add DMARC, SPF and DKIM records on AWS Route 53
Blog

How to add DMARC, SPF and DKIM records on AWS Route 53

A precise, Route 53-specific walkthrough for publishing SPF, DKIM and DMARC: empty Record name versus host names, TXT quoting and 255-character chunking, why DKIM CNAMEs must never become Alias records, and TTL strategy for a safe staged path to p=reject.

9 June 2026 · 15 min read

How to add DMARC, SPF and DKIM records on AWS Route 53

AWS Route 53 is a slightly unusual place to publish email-authentication records, because it is built for engineers running infrastructure on AWS rather than for someone who just wants to paste a DMARC string into a box. The DNS editor uses different vocabulary from most registrars, it has its own rules about quoting and TXT chunking, and it offers a flattening feature (Alias records) that does not apply to the records you care about here. Get those details wrong and your SPF, DKIM or DMARC will silently fail validation even though the record looks present.

This guide is specific to Route 53. It walks through adding the exact TXT and CNAME records for DMARC, SPF and DKIM in the Route 53 console, and it spells out the Route 53-specific gotchas: the empty Record name versus a host name, how Route 53 quotes and splits long TXT values, why you must not turn DKIM CNAMEs into Alias records, and how the Hosted Zone TTL interacts with your staged rollout to enforcement. If you want the underlying theory first, the glossary and what is DMARC are good companions, but everything below assumes you are sitting in front of a Route 53 Hosted Zone.

Before you touch Route 53: confirm this is the authoritative zone

The single most common reason a record published in Route 53 does nothing is that Route 53 is not actually authoritative for the domain. Owning a Hosted Zone is not the same as the world using it.

Route 53 plays two separate roles, and people conflate them:

  • Domain registration. You may have bought the domain through Route 53 (the Registered domains section).
  • DNS hosting. A Hosted Zone holds your records and is served by four assigned name servers, something like ns-123.awsdns-45.com.

A domain is only resolved through a given Hosted Zone if that domain's registrar has the zone's four NS records set as its name servers. If you registered elsewhere (GoDaddy, Namecheap, Cloudflare and so on) but created a Route 53 Hosted Zone, your records will not take effect until you point the registrar's name servers at Route 53. Worse, if you have two Hosted Zones for the same domain (easy to do by accident), only the one whose NS records match the registrar will be live, and you may be editing the dead one.

Confirm what is actually authoritative before you spend an afternoon editing records that nobody queries:

  • In the Route 53 console, open the Hosted Zone and note the four NS values in the auto-created NS record.
  • Check those match the name servers shown at your registrar.
  • Run the DNS record checker against your domain to see what the public internet currently returns, not what the console says it should.

If the live answers do not match your zone, fix the delegation first. Nothing else in this guide matters until queries reach Route 53.

The Route 53 record editor, in plain terms

When you click Create record in a Hosted Zone, Route 53 gives you a small form. The fields that matter for email authentication:

  • Record name. This is the host part, prepended to your domain. Leaving it empty means the record applies to the root (apex) of the domain, for example yourdomain.com itself. Typing _dmarc creates _dmarc.yourdomain.com. Route 53 shows the full name it will create as you type, which is your safety check.
  • Record type. TXT for SPF and DMARC, CNAME for most DKIM (and for any provider that hands you CNAMEs).
  • Value. The record contents. Route 53 is fussy about quoting here, covered in detail below.
  • TTL (seconds). How long resolvers may cache the answer. Route 53 defaults to 300 for new records in the quick-create view but often suggests larger values; you control it.
  • Routing policy. Leave this as Simple routing for all authentication records. Weighted, latency and failover policies are for traffic management and have no place in SPF, DKIM or DMARC.

One Route 53 quirk to internalise now: you can hold multiple values inside a single record of the same name and type. Route 53 expects each TXT string on its own line in the Value box, and it treats them as separate strings within one record set. This matters enormously for SPF, where having two separate SPF records is an error but two strings inside one record is fine.

Adding the SPF record (TXT) in Route 53

SPF lives in a TXT record at the root of your domain. There is no dedicated SPF record type any more; the old SPF type was deprecated, so use TXT.

  1. In the Hosted Zone, click Create record.
  2. Leave Record name empty so the record is created at the apex (yourdomain.com).
  3. Set Record type to TXT.
  4. In Value, paste your SPF string wrapped in double quotes, for example:
"v=spf1 include:_spf.google.com include:amazonses.com -all"
  1. Set TTL to 3600 (one hour) for now.
  2. Choose Simple routing and click Create records.

A few Route 53-specific points that catch people out:

  • Quoting. Route 53 stores TXT values as quoted strings. In the console you should wrap the value in double quotes yourself, as shown. If you paste v=spf1 include:... -all with no quotes, the console will usually accept it and add quoting, but get into the habit of supplying the quotes so the stored value is unambiguous. When you use Terraform, the AWS CLI or the API, quoting rules differ and are a frequent source of malformed records.
  • One SPF record only. You must have exactly one TXT record at the apex that begins with v=spf1. If you already have a TXT at the root (for a domain verification token, say), do not create a second TXT record set that also starts with v=spf1. Either keep all your verification tokens and the SPF string as separate values inside the picture below, or, more cleanly, keep the SPF string in its own dedicated SPF TXT value and unrelated tokens as their own TXT values. Two v=spf1 records resolve to a permerror and SPF fails outright.
  • Stay under ten lookups. Every include, a, mx, ptr and exists mechanism costs a DNS lookup at evaluation time, and SPF caps the total at ten. Route 53 will happily store a record that blows past that limit; it does not validate SPF semantics. If you have stacked up several senders, verify with the SPF checker, and if you are over, our SPF flattening product keeps the published record flat and under the limit automatically as your senders change.

If you would rather assemble the string from a list of senders than hand-write it, the SPF generator produces a single valid record you can paste straight into the Value box.

What about long SPF records and TXT chunking?

A single TXT string cannot exceed 255 characters. SPF records can grow past that once you have several includes. Route 53 handles the overflow by letting you store the value as multiple quoted strings, which DNS concatenates back together at query time with no separator.

In the Route 53 console you express this by putting two quoted strings on consecutive lines in the Value box, or two quoted strings separated by a space, like this:

"v=spf1 include:_spf.google.com include:servers.mcsv.net include:amazonses.com " "include:spf.protection.outlook.com include:sendgrid.net -all"

Note the trailing space inside the first string before the closing quote. Because DNS joins the chunks with no delimiter, you must make sure the join does not glue two mechanisms together (...amazonses.cominclude:spf...). Put the boundary at a natural space. This is exactly the kind of thing that is easy to get wrong by hand; the DNS record splitter chunks a long value into correctly quoted 255-character segments for you. Honestly, though, the better answer for a record this large is to flatten it so it never needs splitting.

Adding DKIM in Route 53

DKIM is where the Route 53 vocabulary trips people most, because almost every sending platform gives you DKIM as CNAME records pointing at the provider, and the host names contain dots and underscores that look alarming in the Route 53 form.

DKIM records live at a selector under the special _domainkey label:

selector._domainkey.yourdomain.com

The selector is chosen by your sending platform. Different providers use different forms: Google uses google, Amazon SES gives you three long random selectors, Mailchimp uses k1 or k2, Microsoft 365 uses selector1 and selector2.

DKIM as CNAME (the common case)

Most modern providers, including SES, Microsoft 365 and Mailchimp, give you CNAMEs so they can rotate the underlying key without you editing DNS again. Adding one in Route 53:

  1. Click Create record.
  2. In Record name, type only the host portion that precedes your domain. If the provider tells you the full name is selector1._domainkey.yourdomain.com, you type selector1._domainkey in the Record name field. Do not type the whole thing including yourdomain.com; Route 53 appends the zone name automatically, and typing it twice produces selector1._domainkey.yourdomain.com.yourdomain.com, a dead record. Watch the full-name preview Route 53 shows.
  3. Set Record type to CNAME.
  4. In Value, paste the target the provider gave you, exactly, for example selector1-yourdomain-com._domainkey.yourdomain.onmicrosoft.com. No quotes around CNAME values.
  5. Set TTL to 3600.
  6. Simple routing, then Create records.

A SES domain typically needs three of these:

abcdefg1234567._domainkey   CNAME   abcdefg1234567.dkim.amazonses.com
hijklmn8901234._domainkey   CNAME   hijklmn8901234.dkim.amazonses.com
opqrstu5678901._domainkey   CNAME   opqrstu5678901.dkim.amazonses.com

The two Route 53-specific DKIM CNAME gotchas:

  • Never convert a DKIM CNAME to an Alias. Route 53 offers an Alias toggle that flattens a record so the apex can point at an AWS resource. Alias is for pointing names at AWS targets such as CloudFront, ELB or S3 website endpoints; it cannot point at an arbitrary external host like dkim.amazonses.com, and it does not return a CNAME at all. Leave Alias off for every DKIM record. If you see an Alias option highlighted, you are on the wrong record type.
  • CNAME and other records cannot coexist on the same name. DNS forbids a CNAME alongside any other record type at the same host. For DKIM this is rarely an issue because the selector name is unique, but if a provider ever asks you to publish both a CNAME and a TXT at the same selector, something is wrong with their instructions.

Verify each selector resolves with the DKIM checker once published.

DKIM as TXT (the public-key case)

Some providers, and any setup where you generate the key yourself, give you the DKIM public key to publish directly as a TXT record at the selector. These get long, well over 255 characters for a 2048-bit key, so the same chunking rule as SPF applies.

  1. Create record, Record name selector._domainkey (host portion only).
  2. Type TXT.
  3. Value: the public key, quoted, split into 255-character chunks across multiple quoted strings:
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234" "567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ...IDAQAB"

The boundary between chunks can fall anywhere inside the base64 p= value because it is concatenated with no separator, but it must split the key into pieces of 255 characters or fewer. Route 53 will reject a single TXT string longer than 255 characters with a Value is too long style error, which is your cue to chunk. The DNS record splitter does this correctly; a 2048-bit key is the textbook case for it. For the trade-offs between 1024-bit and 2048-bit keys, see DKIM key length.

Adding the DMARC record (TXT) in Route 53

DMARC is a TXT record published at the fixed host _dmarc. It is the policy that tells receivers what to do with mail that fails SPF and DKIM alignment, and where to send you the aggregate reports.

  1. Click Create record.
  2. In Record name, type _dmarc (just that; Route 53 makes it _dmarc.yourdomain.com).
  3. Set Record type to TXT.
  4. Paste your DMARC policy, quoted. Start in monitoring mode:
"v=DMARC1; p=none; rua=mailto:reports@yourdomain.com; ruf=mailto:reports@yourdomain.com; fo=1; adkim=s; aspf=s"
  1. Set TTL to 3600.
  2. Simple routing, then Create records.

Route 53-specific and DMARC-specific points:

  • _dmarc is a host name, not the apex. A surprising number of people paste the DMARC string into the root TXT record alongside SPF. That does nothing; receivers look up _dmarc.yourdomain.com specifically. SPF goes at the apex, DMARC goes at _dmarc. They are different records.
  • The reporting address can be on another domain, but then there is an extra step. If rua points at a mailbox on a domain you do not control (a third-party monitoring service, for example), that other domain must publish an authorisation record so it will accept your reports. The error people hit is that reports silently never arrive. The DMARC checker flags external-destination problems.
  • One DMARC record only. As with SPF, two TXT values beginning v=DMARC1 at _dmarc is invalid and many receivers will ignore the policy entirely.
  • Generate it rather than guessing the tags. The combination of p, sp, pct, adkim, aspf, fo, rua and ruf has real consequences. The DMARC generator builds a syntactically correct record from plain-English choices, and understanding your DMARC record explains each tag.

Confirm the published policy with the DMARC checker before moving on.

TTL strategy in Route 53 for a safe rollout

TTL (time to live) is the number of seconds a resolver is allowed to cache your record. Route 53 lets you set it per record, and it matters more for email authentication than people expect, because the whole point of DMARC is a staged rollout where you change the policy several times.

The logic is simple: a high TTL means that when you change a record, the old value lingers in caches around the world for up to that many seconds. A low TTL means changes propagate quickly but resolvers query you more often (a non-issue at Route 53's scale and pricing).

Practical advice for Route 53:

  • While you are actively changing things, keep authentication records at 300 (five minutes). This includes the run-up to a DMARC policy change, when you want a mistake to be reversible in minutes, not hours.
  • Lower the TTL first, then wait, then change the value. If your DMARC record is currently at TTL 3600 and you want to move from p=none to p=quarantine, first edit the record to drop the TTL to 300 and wait at least the old TTL (one hour) so caches expire. Only then change the policy. Otherwise the old p=none can persist in caches for up to an hour after you think you have enforced.
  • Once a record is stable (DKIM CNAMEs that will not change, a settled SPF record), you can raise TTL to 3600 or higher to reduce query volume. There is no deliverability benefit to a high TTL; it is purely about caching.

This TTL discipline is the mechanical half of the real goal, which is reaching enforcement without breaking mail.

The staged path to enforcement, Route 53 edition

Publishing the records is the easy part. The reason DMARC projects stall is the move from p=none to p=reject, where a forgotten sender suddenly gets its mail quarantined or rejected. Route 53 is just the editor here; the method is the same everywhere.

  1. Publish p=none and collect reports. With the DMARC record above live, receivers start sending you aggregate (RUA) reports listing every source sending as your domain and whether it passed aligned SPF or DKIM. Leave this running for two to four weeks.
  2. Read the reports and fix alignment. The reports reveal legitimate senders that are not yet aligned (a SaaS tool you forgot, a regional office, a billing platform). For each, you go back into Route 53 and add the missing SPF include or DKIM CNAME. Raw XML is hard to read by hand; the DMARC report analyzer turns it into a sender-by-sender view, and reading your first DMARC report walks through it.
  3. Move to p=quarantine, optionally with pct. Once every legitimate sender is aligned, edit the _dmarc TXT in Route 53 to p=quarantine. You can ramp with pct=25 and increase, although sampling has caveats covered in pct and sampling.
  4. Move to p=reject. When quarantine has been clean for a couple of weeks, change the policy to p=reject. This is the state Gmail, Yahoo and Microsoft increasingly expect from bulk senders; see Gmail, Yahoo and Microsoft DMARC requirements.

Two enforcement subtleties worth flagging:

  • Subdomains. DMARC at the apex covers subdomains through the inherited sp policy. If you send from mail.yourdomain.com or news.yourdomain.com, decide explicitly with the sp tag rather than letting it default. Subdomain policy with sp covers the gotchas.
  • Forwarding breaks SPF, not DKIM. Mailing lists and forwarders rewrite the path and break SPF alignment, which is exactly why you want DKIM solidly in place: it survives forwarding. DKIM alignment and forwarding explains why this is your safety net at enforcement.

For the full method end to end, reach p=reject without breaking email is the companion to this DNS-editing guide.

Route 53 mistakes that silently break authentication

A consolidated checklist of the failures that are specific to, or especially common in, Route 53:

  • Editing the wrong Hosted Zone. Two zones for one domain; only the one matching the registrar NS is live. Check delegation with the DNS record checker.
  • Doubling the domain name on CNAME host fields. Typing selector._domainkey.yourdomain.com in Record name creates ...yourdomain.com.yourdomain.com. Use the host portion only and watch the preview.
  • Putting DMARC at the apex. DMARC must be at _dmarc, not in the root TXT next to SPF.
  • Two v=spf1 or two v=DMARC1 records. One of each, full stop. Multiple values inside a single record set are fine; multiple record sets that each start the policy are not.
  • An unquoted or unchunked long TXT. Strings over 255 characters must be split into multiple quoted segments, with the boundary on a safe space (SPF) or anywhere (base64 DKIM key).
  • Turning a DKIM CNAME into an Alias. Alias is for AWS targets only; it cannot point at a provider's DKIM host. Keep it off.
  • A high TTL during a policy change. Lower TTL to 300, wait out the old TTL, then change the value.

After every change, do not trust the console; verify against the live DNS. The DMARC checker, SPF checker and DKIM checker read what the world actually resolves, which is the only thing receivers act on.

The practical takeaway

Route 53 is a perfectly good home for SPF, DKIM and DMARC once you respect its three habits: leave Record name empty for the apex and use only the host portion for everything else, quote and chunk long TXT values correctly, and never let a DKIM CNAME become an Alias. The records themselves are the same standards-based strings you would publish anywhere; Route 53 just has opinionated plumbing around them. Publish at p=none, read the reports, align every sender, and only then tighten to quarantine and reject, lowering your TTLs before each policy change so a mistake is always minutes from reversible.

If you would rather not hand-edit chunked TXT records and babysit a staged rollout, that is exactly what we do for you. Our done-for-you DMARC service manages the records on your behalf, SPF flattening keeps you under the ten-lookup limit as senders change, and our monitoring emails you the moment a record drifts or a new sender appears, so a clean Route 53 zone stays clean. Start by running your domain through the DMARC checker to see exactly where you stand today.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.