comail #
ZDS uses Comail as its default email delivery provider. Comail is cooperative email infrastructure for atproto identities: a sending domain is enrolled under an atproto DID, and requests to send mail authenticate with both an API key and that DID.
ZDS uses Comail for account and identity email tokens:
- account email confirmation
- email update confirmation
- PLC operation confirmation
These emails are user-triggered transactional messages. ZDS sends them through
Comail's HTTP Send API with category: "verification", which tells Comail the
message is part of an auth or verification flow rather than broadcast mail.
identity model #
ZDS keeps the PDS service identity separate from the Comail sending identity.
ZDS_SERVER_DIDis the PDS service DID, usuallydid:web:<pds-host>.ZDS_COMAIL_DIDis the atproto DID that enrolled the sending domain with Comail.ZDS_EMAIL_FROMis the bare sender address on that enrolled domain.
For the hosted pds.zat.dev deployment:
ZDS_MAIL_PROVIDER=comail
ZDS_COMAIL_DID=did:plc:mkqt76xvfgxuemlwlx6ruc3w
ZDS_EMAIL_FROM=noreply@zat.dev
That means mail is sent as noreply@zat.dev, authorized by the zat.dev
account DID. It does not mean mail is sent by did:web:pds.zat.dev.
configuration #
The Comail provider uses these ZDS settings:
ZDS_MAIL_PROVIDER=comail
ZDS_COMAIL_API_KEY=...
ZDS_COMAIL_DID=did:plc:...
ZDS_EMAIL_FROM=noreply@example.com
ZDS_EMAIL_FROM must be a bare email address. Comail rejects display-name
forms such as:
ZDS_EMAIL_FROM='ZDS <noreply@example.com>'
That form is accepted by some providers, including Resend, but Comail returns
INVALID_REQUEST.
request shape #
All provider-specific behavior stays in src/core/mail.zig. The rest of ZDS
calls mail.sendCode(...) and does not know which provider is active.
For Comail, ZDS sends:
POST https://smtp.atmos.email/v1/send
Authorization: Bearer <ZDS_COMAIL_API_KEY>
X-Atmos-DID: <ZDS_COMAIL_DID>
Content-Type: application/json
with JSON shaped like:
{
"from": "noreply@example.com",
"to": "user@example.com",
"subject": "Confirm email",
"text": "Hello handle. Your email confirmation code is ABCDE-FGHIJ. This code will expire in ten minutes.",
"category": "verification"
}
ZDS does not log successful message bodies or tokens in production. If Comail returns a non-2xx response, ZDS logs the provider, status code, and a short response excerpt so operators can diagnose configuration or delivery issues.
local development #
Local development can run without Comail secrets. When ZDS_PUBLIC_URL is a
localhost URL and mail config is incomplete, ZDS logs the generated code instead
of sending mail.
For non-local deployments, incomplete mail config is a hard failure. This is intentional: a production PDS should not tell clients that verification mail was sent when the provider was not configured.
operational notes #
- The sending domain must be enrolled in Comail before production delivery will work.
- New domains start in Comail's warming tiers. Verification emails are low volume, but repeated manual retries can still consume the early hourly/daily allowance.
- Keep
ZDS_COMAIL_API_KEYin deployment secrets, not in committed files. - If Bluesky reports "Failed to send email", check Fly logs for
mail delivery failed provider=comail.
Useful Comail docs: