Skip to content

DNS records

Sending-domain setup uses four DNS records and a domain-control proof. The proof can be a TXT record or an AT Protocol handle that already matches the domain.

This page is written for hosted members: you enroll a sending domain, comail’s relay handles outbound delivery and reputation. If you operate your own relay, see self-hosting for the DNS shape on the operator side.

Configuration: Examples below use 203.0.113.77 (RFC 5737 reserved range) as a stand-in for the comail relay’s outbound IPv4. Replace it with the literal IP shown to you during enrollment.

Each enrolled sending domain needs:

  • Two DKIM TXT records (RSA and Ed25519)
  • One SPF TXT record
  • One DMARC TXT record
  • One domain-control proof. Three are accepted: an exact handle match, an _atmos-control.<domain> TXT record (comail’s own namespace, recommended for new enrollments), or an _atproto.<domain> TXT record (the historical proof; kept primary for domains that already verify through it).

Enrollment shows the exact values for whichever case applies; this page explains what each record does and how to verify it.

The labeler tries three proofs in this order, and the first one that matches wins:

  1. Handle match. If your atproto handle equals the sending domain (alice.com enrolling alice.com, or bsky.app enrolling bsky.app), handle resolution already proves you control the domain. Publish no extra control record.
  2. _atmos-control.<domain> TXT. A TXT record in comail’s own namespace carrying did=<your DID>. This is comail’s canonical control record. It lives independently of your atproto handle, so it works regardless of who owns _atproto.<domain>. Recommended for any new enrollment where your handle differs from the sending domain.
  3. _atproto.<domain> TXT. The atproto handle record. If it already names your DID, the labeler accepts it as proof of control too.

Handle matching is live proof, not a permanent enrollment grant. Comail checks it again when accepting a message and before releasing queued mail. If the handle changes, new sends are rejected and queued mail cannot be released unless _atmos-control or _atproto still names the account’s DID. Accounts that change handles regularly should publish _atmos-control as a stable fallback even while the handle matches.

_atmos-control is additive: a domain that already verifies through _atproto keeps verifying, and the account page keeps treating _atproto as the primary record so nothing churns.

DKIM (dual signature)

Every outbound message carries two pairs of DKIM signatures: RSA and Ed25519 from your domain, plus RSA and Ed25519 from d=atmos.email. The operator-domain pair lets the relay pool reputation across members at the atmos.email level while your domain’s pair remains aligned for DMARC.

Your domain’s signature uses two algorithms (RSA and Ed25519) so mailbox providers can pick whichever they prefer. The records look like:

<selector>r._domainkey.yourdomain.com TXT "v=DKIM1; k=rsa; p=<public-key>"
<selector>e._domainkey.yourdomain.com TXT "v=DKIM1; k=ed25519; p=<public-key>"

The selector is a short identifier issued at enrollment. The r and e suffixes mark the algorithm.

dig +short TXT <selector>r._domainkey.yourdomain.com

Should return a v=DKIM1; k=rsa; p=... record. Do the same for the e selector.

DNS dashboards and zone files use different formats. The RSA public key produces a TXT value over 255 characters. In a DNS provider’s TXT value field, paste the one-line value comail gives you without adding quotation marks. The provider will store it as the logical TXT value.

Zone files must split that value into adjacent quoted strings because each DNS character-string is limited to 255 bytes. The DNS zone export on your domain page handles this for you:

<selector>r._domainkey.yourdomain.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBg..." "...rest"

Do not paste the zone-file quote separator into a single dashboard field: some providers publish those quote characters literally, which makes the DKIM key invalid. If your provider exposes separate string fields, split the value between those fields without including the quotation marks. The Ed25519 record is short and does not need splitting.

SPF

SPF authorizes the relay’s IP to send on behalf of your domain. Add this TXT record at your domain’s apex:

@ TXT "v=spf1 ip4:203.0.113.77 -all"

The -all suffix returns an SPF failure for sources outside the list. Receivers decide how to handle that result. If you use another sending service, include its required mechanisms in the same SPF record; do not publish a second SPF record.

dig +short TXT yourdomain.com

Look for the v=spf1 record in the output.

DMARC

DMARC tells receivers what to do when SPF or DKIM alignment fails. The recommended record:

_dmarc TXT "v=DMARC1; p=reject; adkim=r; aspf=r; rua=mailto:postmaster@atmos.email"

Field meanings:

  • p=reject: receivers should reject mail that fails alignment.
  • adkim=r: relaxed DKIM alignment. The signing domain and visible From domain must share the same organizational domain.
  • aspf=r: relaxed SPF alignment.
  • rua=mailto:postmaster@atmos.email: requests aggregate reports at the operator address. Reports to an unrelated domain require authorization in that destination’s DNS. Setting rua alone does not prove reports arrive. You can also use a reporting address you control.
dig +short TXT _dmarc.yourdomain.com

Domain control record

If your sending domain matches your atproto handle, skip this section. Otherwise, publish one of the two TXT records below at the sending domain.

The DID value you use is whatever https://<your-handle-domain>/.well-known/atproto-did returns, or whatever the DNS-based handle resolution at your handle domain points at.

_atmos-control.mail.example.com TXT "did=did:plc:abc123def456..."

This record lives in comail’s own DNS namespace. It is decoupled from atproto handle resolution, so it proves control even when _atproto.<domain> is occupied by a different DID. Use this record for any new enrollment where your handle does not equal the sending domain.

Why it exists: a sending domain can also be a different atproto account’s handle. When that happens, _atproto.<domain> already carries the other DID’s value and the labeler’s _atproto-only check could never match. _atmos-control.<domain> sits outside that namespace and proves your DID controls the domain without colliding with anyone else’s handle.

dig +short TXT _atmos-control.mail.example.com

Should return a single did=did:... record matching your DID exactly.

If your domain already verifies through this record from a prior enrollment, leave it in place. The labeler still accepts it and treats it as your primary control proof.

_atproto.mail.example.com TXT "did=did:plc:abc123def456..."

The atproto labeler reads this TXT record the same way handle resolution would if your handle were the sending domain.

dig +short TXT _atproto.mail.example.com

Should return a single did=did:... record matching your DID exactly.

Alignment, in plain language

“Alignment” is the rule that ties an authentication signal back to the domain in the From: header. DMARC requires at least one of SPF or DKIM to align.

  • Your DKIM signature uses d=yourdomain.com, which aligns with a From address on that domain.
  • The relay’s d=atmos.email signature does not align with your domain. That’s fine; only one needs to align.
  • SPF checks the envelope return-path (MAIL FROM). A return-path on atmos.email does not align with an unrelated member domain, even with aspf=r. Mail using that return-path relies on the member-domain DKIM signature for DMARC alignment.

See the DMARC specification for alignment and external report authorization.

Once DKIM is live in DNS, the labeler issues a verified-mail-operator label on your DID. The relay watches for this label and uses it as proof of DNS authentication. See Atproto labels for what each label means and how to query them.

If the labeler can’t verify your DKIM (because the DNS record is missing, mistyped, or hasn’t propagated yet), enrollment will retry. You can check status at /account.

Back to docs