16 June 2026 · 16 min read
DigitalOcean is a developer-first cloud, and its DNS service reflects that: it is a clean, fast, free hosted DNS that comes bundled with your account and is managed either through the Networking then Domains panel in the control panel, with doctl on the command line, or through the API and Terraform. It does a few things very well and a few things not at all, and the gap between those two lists is exactly where DMARC, SPF and DKIM go wrong. Most importantly, DigitalOcean does not do TXT chunking for you, it has a particular convention for the hostname field that catches people out, and its CNAME handling at the apex is stricter than hosts like Cloudflare. This guide is specific to the DigitalOcean DNS editor. It is not a generic "what is DMARC" piece; if you need that grounding first, read What is DMARC, What is SPF and What is DKIM, then come back here to actually publish the records.
Everything below assumes DigitalOcean is your authoritative DNS, meaning your domain's nameservers at the registrar point to DigitalOcean's three nameservers (ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com). If your registrar still answers DNS and you only use DigitalOcean for Droplets, the records below must go wherever your DNS actually lives, not here. Confirm where your zone is served from with the DNS record checker before you touch anything.
Before you start: is the domain actually delegated to DigitalOcean?
A surprising number of "my DKIM will not resolve" tickets come down to DigitalOcean not being authoritative for the zone at all. You can add a domain under Networking then Domains and start creating records, but DigitalOcean only serves them once the registrar's NS records point at it.
- Open Networking then Domains and confirm the domain is listed. DigitalOcean creates an NS record set and an SOA automatically when you add it.
- At your registrar, set the nameservers to
ns1.digitalocean.com,ns2.digitalocean.comandns3.digitalocean.com. - Wait for the registrar's own TTL on the delegation to expire (this can take from minutes to a couple of days the first time).
Until that delegation is live, anything you add in the DigitalOcean panel is invisible to the internet. Run a baseline so you know your starting point: check your current policy with the DMARC checker, your sending record with the SPF checker, and any existing signatures with the DKIM checker. Knowing the "before" stops you chasing a fault that was already there.
The three records and where they live
The single most common publishing mistake on any host is putting the right value at the wrong name. Pin the target names down first, because DigitalOcean's hostname field behaves slightly differently from what you might expect.
- SPF is one TXT record at the root of your domain. On DigitalOcean you put
@in the HOSTNAME field, and the panel shows it back to you as your bare domain (example.com). The value starts withv=spf1. You must have exactly one SPF record; two is a permanent error. - DMARC is one TXT record at the subdomain
_dmarc. You put_dmarcin the HOSTNAME field, and DigitalOcean turns that into_dmarc.example.com. The value starts withv=DMARC1. - DKIM is published per selector at
selector._domainkey. You put something likes1._domainkeyorgoogle._domainkeyin the HOSTNAME field, givings1._domainkey.example.com. The value is either a long TXT public key, or a CNAME pointing at your sending platform's hosted key, depending on the platform.
There is one rule that matters more on DigitalOcean than on some hosts: enter the hostname prefix only, never the fully qualified name. DigitalOcean appends the zone (.example.com) for you. If you type _dmarc.example.com into HOSTNAME, you create _dmarc.example.com.example.com, which resolves to nothing and produces a "no DMARC record" result even though the record visibly exists in the panel. Type only _dmarc, @, or s1._domainkey. If you genuinely need to enter an absolute name (you almost never do for these three records), DigitalOcean honours a trailing dot to mean "this is already fully qualified", but for SPF, DMARC and DKIM you should be entering the short prefix and letting the panel complete it.
Underscores are literal and mandatory: _dmarc and _domainkey keep their leading underscore. DigitalOcean handles underscores fine; the mistake is people dropping them, not the editor refusing them.
Adding a record in the DigitalOcean DNS editor, step by step
The mechanics are the same idea for all three record types, with a per-type tab across the top of the record creation row.
- Go to Networking then Domains and click into your domain.
- Across the "Create new record" row, pick the tab: TXT for SPF and DMARC, and either TXT or CNAME for DKIM depending on your platform.
- In HOSTNAME, enter the prefix only (
@,_dmarc, orselector._domainkey). - In VALUE (TXT) or WILL DIRECT TO (CNAME), paste the value. For TXT, paste it as one continuous string with no surrounding quotes: DigitalOcean adds the quoting itself when it stores the record.
- Set TTL. DigitalOcean defaults to 3600 seconds (one hour). Lower it to 1800 or even 300 while you are actively changing records, then it is your call whether to raise it again.
- Click Create Record.
Concrete examples, entered exactly as shown.
DMARC, starting at monitoring policy. Tab TXT, HOSTNAME _dmarc, VALUE:
v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com; fo=1; adkim=s; aspf=s
SPF for a domain sending through Google Workspace plus one marketing tool. Tab TXT, HOSTNAME @, VALUE:
v=spf1 include:_spf.google.com include:servers.mcsv.net -all
DKIM as a CNAME (the common case for Google Workspace, Amazon SES, Mailgun, Postmark and most platforms that host the key for you). Tab CNAME, HOSTNAME google._domainkey, WILL DIRECT TO the host your provider gives you, for example:
google._domainkey.example.com -> ghs.googlehosted.com.
Note the trailing dot DigitalOcean shows on CNAME targets: that is normal and correct, it marks the target as a fully qualified name. DKIM as a TXT public key (when you generate the key yourself) goes in the TXT tab, HOSTNAME s1._domainkey, and the VALUE is the full v=DKIM1; k=rsa; p=MIIBIjANBgkq... string. That long key is where DigitalOcean's biggest gotcha lives, so it has its own section below.
If you have not worked out the DMARC value yet, build one with the DMARC generator and assemble SPF with the SPF generator so you start from a syntactically valid string rather than hand-typing tags.
The big one: DigitalOcean does NOT chunk long TXT records for you
This is the most important DigitalOcean-specific point in the whole guide, and the one that breaks the most DKIM keys.
A single DNS character-string is capped at 255 bytes. A 2048-bit DKIM public key in a TXT record is comfortably longer than that, often around 380 to 420 characters. Some DNS hosts (Cloudflare, Route 53's console in many cases) accept the whole key as one line and silently split it into correctly quoted 255-byte chunks for you. DigitalOcean's panel does not do this reliably, and historically it has let you paste an over-length value that then serves incorrectly. The symptom is brutal and confusing: the record exists, the panel shows it, but the DKIM checker reports the key as invalid or truncated, and signed mail fails DKIM at the receiver.
The safe way to publish a long DKIM key on DigitalOcean is to split it yourself into 255-character or shorter chunks, each wrapped in its own pair of double quotes, separated by a space, all on one logical line. A correctly split DKIM TXT looks like this in concept:
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0a1b2c...firstchunk" "...secondchunk...continues...thirdchunk...to the end of the base64 key"
The receiver concatenates the chunks back into one string with no separator, so the split point can fall anywhere in the base64; you do not need to break it at a tag boundary. What you must not do is introduce stray characters, lose a chunk, or leave the whole thing as a single 400-character string and hope.
You do not have to count characters by hand. Use our DNS record splitter: paste the full DKIM key, and it returns the correctly chunked, quoted multi-string form ready to paste into DigitalOcean's VALUE field. Then, after you save, verify by lookup, not by the panel. DigitalOcean showing "saved" only means the row exists; it says nothing about whether the key parses. Run the DKIM checker and confirm the public key is read back in full. For background on why the chunk boundary exists and how selectors work, see DKIM selectors explained.
The good news: SPF and DMARC values are almost always well under 255 characters, so chunking is a DKIM-only concern in practice. But it is the concern that costs people the most time on DigitalOcean specifically, precisely because hosts that auto-chunk have trained everyone to paste blindly.
CNAME at the apex: DigitalOcean follows the standard strictly
DigitalOcean does not offer CNAME flattening at the zone apex the way Cloudflare does. It follows the DNS standard: you cannot have a CNAME at the root (example.com) coexisting with the SOA and NS records that must live there. This matters for authentication in one specific way.
- Never try to "delegate" your SPF with a root CNAME. Some guides for other providers suggest CNAMEing the apex to a managed SPF record. On DigitalOcean that simply will not work: the apex CNAME is rejected or conflicts with the mandatory apex records, and even where a host allows it, flattening only resolves address records, not the TXT that SPF needs. Publish SPF as a plain TXT at
@. Full stop. - DKIM CNAMEs are never at the apex, so this restriction does not touch them. DKIM lives at
selector._domainkey, a subdomain, where ordinary CNAME rules apply. The CNAME resolves normally to your provider's key host. So for standard DKIM you do not need to think about apex behaviour at all; you only meet the restriction if you deliberately try to CNAME the root, which you should not do for any of these three records.
If you are pointing your apex at a web app and wondering about flattening, that is a website concern, not an email-authentication one, and it does not interact with SPF, DMARC or DKIM. Keep the two problems separate in your head.
SPF on DigitalOcean: one record, watch the lookup count
SPF has two pitfalls on DigitalOcean beyond the universal "exactly one record" rule.
First, the panel will happily let you create two TXT records at @ that both start with v=spf1. DigitalOcean does not deduplicate, merge or warn you. Two SPF records is a permerror, and every receiver treats it as a hard failure regardless of how correct each one is on its own. When you add a new sending platform, edit your existing SPF record to add the new include:, do not create a second SPF TXT. After editing, confirm there is exactly one with the SPF checker.
Second, DigitalOcean does not flatten SPF or count your DNS lookups for you. SPF allows a maximum of ten DNS-resolving mechanisms across the whole record (include, a, mx, ptr, exists, redirect). Stack up Google Workspace, a CRM, a help desk and a marketing tool and you can quietly cross ten, producing a permerror and an SPF failure no matter how correct each include is individually. DigitalOcean gives you no signal that this has happened, because to DigitalOcean it is just a string. The classic fix is flattening (resolving the includes down to IP ranges so the record stays under the limit), which DigitalOcean does not do natively. Read SPF PermError: too many DNS lookups and Fix SPF PermError; and our hosted SPF flattening maintains a single flat record under the limit and updates it as your senders change.
One syntax note DigitalOcean stores faithfully but people still get wrong: use -all (hard fail) for a locked-down domain and ~all (soft fail) only while you are still discovering senders. The choice only matters at the receiver, but get it right deliberately rather than by accident.
DMARC on DigitalOcean: start at monitoring, then tighten
The DMARC record is a single TXT at _dmarc. Start in monitoring mode so you gather data before any mail is affected:
v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com; fo=1; adkim=s; aspf=s
A few details that matter on DigitalOcean and in DMARC generally:
- Put a real, monitored mailbox in
rua. Aggregate (RUA) reports are XML, sent daily by receivers, and are how you learn which sources send as your domain before you enforce. DigitalOcean does not parse them, store them or notify you. Pipe them into the DMARC report analyzer or turn on emailed monitoring so the XML becomes a readable picture rather than an inbox full of attachments. - External RUA destinations need authorisation. If your
ruamailbox is on a different domain from the one being protected, that other domain must publish a_report._dmarcauthorisation TXT. If you keep RUA on the same domain, you skip this. It is a DMARC rule, not a DigitalOcean one, and DigitalOcean will not warn you either way. - Move through the policy stages deliberately.
p=nonetop=quarantinetop=reject, usingpctfor sampling andspfor subdomain policy as controls. The reasoning and pacing are in DMARC policy: none vs quarantine vs reject, and the alignment tagsadkim/aspfare explained alongside the common errors in Common DMARC mistakes.
Do not jump to p=reject on day one. The entire reason for starting at none, on DigitalOcean or anywhere, is to see your real sending sources in the reports first, fix any that fail alignment, then enforce. The staged route is laid out in Reach p=reject without breaking email.
DKIM on DigitalOcean: CNAME where you can, TXT where you must
Most modern sending platforms ask you to publish DKIM as a CNAME so they can rotate the underlying key without you touching DNS again. That is the easy path on DigitalOcean: use the CNAME tab, put the selector host (s1._domainkey, google._domainkey, whatever the platform specifies) in HOSTNAME, and the provider's target host in WILL DIRECT TO. DigitalOcean appends the trailing dot to mark the target as absolute. There is no proxy toggle to worry about on DigitalOcean (unlike Cloudflare's orange cloud), so a CNAME here simply resolves the way DNS intends.
The TXT path is the one with teeth, and it is covered in the chunking section above: split the key into quoted 255-byte chunks, paste them as one logical line, and verify the whole key reads back with the DKIM checker. If your platform offers both CNAME and TXT, prefer CNAME on DigitalOcean specifically, precisely because it sidesteps the chunking trap entirely.
When you later rotate a DKIM key, publish the new selector alongside the old one, switch signing, then remove the old selector after a cache-clearing interval. The overlap technique and the timing are in DKIM key rotation, and the trade-off between 1024-bit and 2048-bit keys (which is what makes the chunking question appear at all) is in DKIM key length: 1024 vs 2048.
TTL on DigitalOcean: default is an hour, lower it before changes
TTL (time to live) is how long resolvers cache a record. DigitalOcean's default for new records is 3600 seconds (one hour), and there is also a per-domain default TTL you can set at the top of the domain page.
- An hour is fine for steady state but slow for cutover. If you are mid-rollout and tweaking records, drop the TTL to 300 seconds (five minutes) so mistakes do not stay cached for an hour while you fix them.
- Lower the TTL before a planned change, not at the same time. TTL only governs how long the old value stays cached. If you are about to rotate a DKIM key or tighten SPF and you want a fast cutover, set the TTL low first, wait for the previous TTL to expire, then make the change. Lowering it in the same save as the change does nothing for the already-cached old value.
- "Saved on DigitalOcean" is not "live everywhere". Even with a five-minute TTL, a resolver that fetched the record ten minutes ago under the one-hour default will hold the stale value until its own cache expires. Check propagation with the DNS propagation checker rather than assuming the panel and the public DNS agree yet.
How long this actually takes in practice, and why it is not instant, is covered in How long do DNS changes take and the broader propagation behaviour you should expect.
Editing and rollback: export your zone first
DigitalOcean does not keep a per-record version history you can click to restore. When you edit a record and save, the old value is gone from the panel. A couple of habits make changes safe:
- Copy the current value into a note before editing, especially for SPF and the DKIM key, so you can restore it by hand if the change misbehaves.
- Use
doctlor the API to snapshot the zone. Runningdoctl compute domain records list example.com --format Type,Name,Data,TTLdumps every record to your terminal; save that output before a round of authentication changes and it becomes your rollback reference. This is also the fastest way to spot a duplicate SPF record or a stray TXT that the panel's scroll hides. - Change one record at a time and verify before moving on. Add or edit DKIM, confirm with the DKIM checker; edit SPF, confirm with the SPF checker; then touch DMARC and confirm with the DMARC checker. Batching all three and then discovering a failure leaves you guessing which one broke it.
Doing it at scale: doctl, the API and Terraform
DigitalOcean is a developer cloud, so the dashboard is rarely the only route. The same DNS operations are available on the command line and as code, which suits authentication records because they template cleanly and benefit from review.
- doctl.
doctl compute domain records create example.com --record-type TXT --record-name _dmarc --record-data "v=DMARC1; p=none; rua=mailto:dmarc-rua@example.com" --record-ttl 1800creates the DMARC record in one command. The same shape works for SPF (--record-type TXT --record-name @) and DKIM CNAMEs (--record-type CNAME --record-name google._domainkey --record-data ghs.googlehosted.com.). - API. A
POSTto/v2/domains/{domain}/recordswith a JSON body specifyingtype,name,dataandttldoes the same. For a long DKIM TXT key over the API, pass the already-chunked, quoted string asdata; the chunking responsibility is yours, not the API's. - Terraform. The
digitalocean_recordresource lets you declare SPF, DMARC and DKIM as code across many domains, with the value, type, name and TTL all version-controlled and code-reviewed. This is the cleanest way to keep dozens of zones consistent and to audit who changed an authentication record and when.
Whichever route you use, the rules from this guide do not change: one SPF TXT at @, one DMARC TXT at _dmarc, DKIM per selector, prefer CNAME for DKIM, and split any long DKIM TXT key into quoted 255-byte chunks yourself because DigitalOcean will not.
A quick end-to-end checklist
Run through this after publishing on DigitalOcean:
- The domain is delegated to DigitalOcean's nameservers and DigitalOcean is authoritative, confirmed by lookup, not just listed in the panel.
- Exactly one SPF TXT at
@, under ten DNS lookups, ending in-allor~allas intended. - One DMARC TXT at
_dmarc, starting atp=none, with a realruamailbox you actually read. - DKIM published per sending platform: CNAME where the platform supports it, and any TXT key split into quoted 255-byte chunks and verified to read back in full.
- TTL lowered (300 to 1800 seconds) while you are making changes; the one-hour default is fine once you are stable.
- No duplicate SPF or stray DKIM rows hiding below the fold, checked with
doctl ... records list. - Everything verified by lookup: DMARC checker, SPF checker, DKIM checker, and DNS propagation checker, not by the panel's "saved" message.
The takeaway
DigitalOcean's DNS is fast, free and pleasant to script against, and for SPF and DMARC it is genuinely simple: one TXT each, at @ and _dmarc, no quoting or chunking to think about. The one place it differs sharply from the friendlier hosts is the long DKIM TXT key: DigitalOcean does not chunk it for you, so a blind paste of a 2048-bit key is the classic way to end up with a record that exists in the panel and still fails verification. Split it into quoted 255-byte chunks (the DNS record splitter does this for you), or sidestep the whole issue by publishing DKIM as a CNAME where your platform allows. Beyond that, the discipline is the same on every host: right type, right hostname (prefix only, let DigitalOcean append the zone), exactly one SPF, monitor first with p=none, and verify by lookup rather than trusting the dashboard.
When you are ready to move from "the records exist" to "the records are correct and enforced", the staged path to p=reject is the real work, and it is exactly what we automate. See hosted DMARC, hosted SPF and hosted DKIM for the done-for-you route, where we keep the SPF record flat and under ten lookups, manage DKIM keys and their chunking, and walk your domain safely to enforcement. Or start free by pointing the DMARC checker at your domain and turning on emailed monitoring, so any future change to these DigitalOcean records pages you the moment it happens.