Add DigitalOcean provider support
Add digitalocean as a remediation provider in records.json so both the CLI
(--provider digitalocean) and the web app emit DigitalOcean-control-panel-specific
fix instructions for the 13-record Thundermail set (1 MX, 5 SRV, 4 TXT, 3 DKIM CNAME).
Internal ticket: TBPRO 7012
(7012_DNS_DIGITAL_OCEAN).
⚠️ Ship as UNVERIFIED first. The SRV field layout below is confirmed from a
screenshot of the live DigitalOcean Create a record dialog; the MX/TXT/CNAME field
labels come from DigitalOcean's official
How to Create, Edit, and Delete DNS Records
docs, not a live add-record screenshot. Follow the godaddy/ionos/ovh/hover precedent:
prefix each header string UNVERIFIED — until confirmed end-to-end, then drop the
prefix.
🎯 example.com is the verification target — it's DigitalOcean-hosted
(ns1/ns2/ns3.digitalocean.com). Query it authoritatively with
--resolver ns1.digitalocean.com.
✅ The trailing-dot rule is now confirmed live on example.com. Its 5 SRV records were
entered without a trailing dot, so DigitalOcean appended the zone name to the target:
$ dig +short SRV _jmap._tcp.example.com
0 1 443 mail.thundermail.com.example.com. # should be mail.thundermail.com
This proves DigitalOcean SRV targets must be entered as {target}. with the trailing
dot. (Its MX target came back correctly as mail.thundermail.com., so confirm whether MX
tolerates a missing dot or was simply entered with one.) ⚠️ Note the checker currently
reports example.com as a false 13/13 because of an unanchored substring match — see
#10; that bug should be fixed so these broken SRV targets show as FAIL.
Add-record model
DigitalOcean uses a single "Create a record" dialog with a Record Type dropdown (like
bunny/godaddy/hover, not per-type sections like cosmotown).
Path: Control Panel → Networking → Domains → select your domain → Create a record →
choose Record Type, fill fields, Create Record. TTL defaults to 3600.
Key conventions (from the docs + the live SRV screenshot):
- Apex host = literal
@ for MX and TXT ("Use @ to create the record at the domain
root"). This is the {host}/@ pattern like godaddy/ionos/hover, not the
blank-apex pattern of bunny/cosmotown/ovh.
- SRV keeps the
_service._protocol label combined in the Hostname field (the
screenshot placeholder is literally e.g. _service._protocol, one field). DigitalOcean
does NOT split Service/Protocol into separate inputs the way godaddy/ionos/hover
do — so use {host} and not the {service}/{protocol} tokens.
- ⚠️ Targets require a trailing dot. The SRV Will direct to doc is explicit: an FQDN
must be entered "with a period (.) at the end. This distinguishes it from a subdomain
prefix" — otherwise DigitalOcean appends your domain. Since all our targets are external
FQDNs (mail.thundermail.com, tmN.<domain>.dkim.thunderhosted.com), encode targets as
{target}. (same trailing-dot handling as ovh). Confirm this also applies to the MX
"Mail provider's mail server" and CNAME "Is an alias of" fields (the docs only spell it
out for SRV, but DO's general behaviour is to append the domain when no dot is present).
- No new interpreter token needed —
{host}, {target}, {value}, {priority},
{weight}, {port} already cover everything.
Field mapping
SRV field order matches the screenshot (Record Type → Hostname → Will direct to → Port →
Priority → Weight → TTL):
| Type |
Fields (DigitalOcean label → value) |
| MX |
Type=MX, Hostname={host} (@), Mail provider's mail server={target}., Priority={priority} |
| SRV |
Type=SRV, Hostname={host} (_jmap._tcp), Will direct to={target}., Port={port}, Priority={priority}, Weight={weight} |
| TXT |
Type=TXT, Hostname={host} (@), TXT Value={value} |
| CNAME |
Type=CNAME, Hostname={host}, Is an alias of={target}. |
Note: SPF, MTA-STS, TLSRPT and DMARC are all plain TXT records on DigitalOcean (the
docs note SPF/DKIM are "special TXT records" created via the TXT option) — DKIM here is a
CNAME, so it uses the CNAME form.
Work items
Reference docs
Local source: THUNDERBIRD_2023/TBPRO/7012_DNS_DIGITAL_OCEAN/7012-DNS-digitalocean-srv.png
(live SRV Create a record dialog).
🤖 Generated with Claude Code
Add DigitalOcean provider support
Add
digitaloceanas a remediation provider inrecords.jsonso both the CLI(
--provider digitalocean) and the web app emit DigitalOcean-control-panel-specificfix instructions for the 13-record Thundermail set (1 MX, 5 SRV, 4 TXT, 3 DKIM CNAME).
Internal ticket: TBPRO 7012
(
7012_DNS_DIGITAL_OCEAN).Add-record model
DigitalOcean uses a single "Create a record" dialog with a Record Type dropdown (like
bunny/godaddy/hover, not per-type sections likecosmotown).Path: Control Panel → Networking → Domains → select your domain → Create a record →
choose Record Type, fill fields, Create Record. TTL defaults to 3600.
Key conventions (from the docs + the live SRV screenshot):
@for MX and TXT ("Use @ to create the record at the domainroot"). This is the
{host}/@pattern likegodaddy/ionos/hover, not theblank-apex pattern of
bunny/cosmotown/ovh._service._protocollabel combined in the Hostname field (thescreenshot placeholder is literally
e.g. _service._protocol, one field). DigitalOceandoes NOT split Service/Protocol into separate inputs the way
godaddy/ionos/hoverdo — so use
{host}and not the{service}/{protocol}tokens.must be entered "with a period (
.) at the end. This distinguishes it from a subdomainprefix" — otherwise DigitalOcean appends your domain. Since all our targets are external
FQDNs (
mail.thundermail.com,tmN.<domain>.dkim.thunderhosted.com), encode targets as{target}.(same trailing-dot handling asovh). Confirm this also applies to the MX"Mail provider's mail server" and CNAME "Is an alias of" fields (the docs only spell it
out for SRV, but DO's general behaviour is to append the domain when no dot is present).
{host},{target},{value},{priority},{weight},{port}already cover everything.Field mapping
SRV field order matches the screenshot (Record Type → Hostname → Will direct to → Port →
Priority → Weight → TTL):
MX, Hostname={host}(@), Mail provider's mail server={target}., Priority={priority}SRV, Hostname={host}(_jmap._tcp), Will direct to={target}., Port={port}, Priority={priority}, Weight={weight}TXT, Hostname={host}(@), TXT Value={value}CNAME, Hostname={host}, Is an alias of={target}.Work items
digitaloceanprovider block torecords.json(headersUNVERIFIED —prefixed), using
{host}for apex/SRV and{target}.for MX/SRV/CNAME targets.uv run verify_thundermail_dns.py example.com --provider digitaloceanrenders all 13records in both
--fix-formattable and long without error.README.mdprovider list + RELEASE_NOTES / RELEASE_NOTES.html.CLAUDE.mdcrucial-decisions with DigitalOcean's quirks (combined SRVHostname,
@apex, trailing-dot targets).example.com(--resolver ns1.digitalocean.com): confirm thetrailing-dot rule on MX/CNAME targets against a live panel (SRV already confirmed),
then drop the
UNVERIFIED —prefixes. NB:example.com's SRV records are currentlybroken (target has
.example.comappended) — fixing them there is itself a good livetest of the emitted
digitaloceanSRV fix strings.Reference docs
Local source:
THUNDERBIRD_2023/TBPRO/7012_DNS_DIGITAL_OCEAN/7012-DNS-digitalocean-srv.png(live SRV Create a record dialog).
🤖 Generated with Claude Code