Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

domain-sithbit: domain verification

Standard port(s): bind 8181, health 8192.

DNS-based domain verification and on-chain domain authorization: it checks a domain’s _solana.authority.<domain> TXT record, then — if configured with the delegate key — submits the on-chain CreateDomain authorization for you.

When you need it: only if you want to offer a self-service “prove you own this domain” flow instead of having the delegate holder run sithbit domain create by hand for every domain operator. One deployment (one delegate key) serves claims for any number of domains, and the same authority key may claim several — the service is stateless per request.

Quickstart:

cargo run -p domain-sithbit

Config file domain_sithbit.toml, or point DOMAIN_SITHBIT_CONFIG at an alternate path.

Note: without delegate_key_file configured, POST /domain replies 503 — DNS verification lookups still work, but on-chain authorization is disabled until a delegate key is set. delegate_key_file is a key source: a bare string is a local file path, and the table form fetches the keypair JSON from a cloud secret manager (kind = "akv", "asm", or "gsm"). The key is re-loaded from the configured source on every POST /domain, so a delegate rotation takes effect by swapping the file (or cloud secret) in place — no restart. Whichever source is configured is validated at boot: an unreadable or malformed key fails startup, not the first request.

This service’s DNS flow is covered in depth in DNS setup; see the Configuration reference for the full key/default table.

Client autoconfiguration (no plugin)

Beyond domain verification, domain-sithbit doubles as the client-autoconfiguration endpoint that lets an unmodified Thunderbird or Outlook fill in its own IMAP/ POP/SMTP settings when a user types a <wallet-base58>@<domain> address into the native Add Account wizard. No SithBit plugin is installed on the client — the wizard fetches a settings document from this service and auto-fills the connection fields.

Three routes serve those documents from the [mail_hosts] coordinates (next section):

RouteMethodClientPurpose
/.well-known/autoconfig/mail/config-v1.1.xmlGETThunderbirdMozilla autoconfig, served from the mail domain itself
/mail/config-v1.1.xmlGETThunderbirdThe same document on the autoconfig.<domain> host — the domain is read from the ?emailaddress= query, else the Host header (any autoconfig. prefix stripped)
/autodiscover/autodiscover.xmlPOSTOutlookPlain-old-XML (POX) autodiscover; the account address is read from the posted body

For both clients the advertised username is the wallet address (the base58 public key): the Thunderbird document uses the %EMAILLOCALPART% placeholder and the Outlook <LoginName> is the local part of the posted address, so a <wallet>@<domain> address logs in as just the wallet — the @domain is never leaked into the credential.

These routes fill in connection settings only — they do not create the account. Native account auto-provisioning is deliberately not offered: the mailbox must already exist on-chain (sithbit mailbox create), and the user still needs a mail credential (next paragraph). The wizard only saves the operator round-trips of hand-entering hostnames, ports, and TLS modes.

After the wizard auto-fills the settings, the user obtains a mail password — the wallet-signature credential their client authenticates with — from either the self-serve enrollment page or the CLI (sithbit mailbox credentials). See Connect a standard mail client for the end-to-end user walk-through.

Hosting the enrollment page

The enrollment page (enroll.html, default URL /addin/enroll.html) is served by account-api from its [static] mount, not by this service. It walks a user through wallet-challenge login and setting (or deriving) their mail password entirely client-side. Because every signature is produced in the browser by the mail_wasm WebAssembly module, that module’s built wasm/ bundle must be deployed beside enroll.html — point [static] root at a directory containing both enroll.html and the wasm/ directory, or drop the enroll.* files into the existing web-client bundle root that already ships wasm/. Without the bundle in place the page loads but cannot sign, so login fails.

The [mail_hosts] config

[mail_hosts] declares the public IMAP/POP/SMTP coordinates the autoconfig/autodiscover documents advertise. Every field is dev-defaulted to a loopback stack on the standard implicit-TLS mail ports, so an empty config still serves a valid (loopback) settings document — point the hosts at your real, publicly reachable mail servers before advertising them.

Sub-tablehost defaultport defaultsocket_type default
[mail_hosts.imap]127.0.0.1993SSL
[mail_hosts.pop]127.0.0.1995SSL
[mail_hosts.smtp]127.0.0.1465SSL

socket_type is one of SSL (implicit TLS from connect), STARTTLS (opportunistic upgrade after connect), or plain (no encryption — dev only). Those are the Thunderbird tokens; lowercase aliases (ssl, starttls) are also accepted, and the Outlook POX flags are derived from them automatically.

A present [mail_hosts.<server>] sub-table must spell out all three fields — a partial table fails startup loudly rather than mixing your host with a surprising default port. An omitted whole sub-server falls back to its defaults above. Individual fields override via env, e.g. DOMAIN_SITHBIT_MAIL_HOSTS__IMAP__HOST=imap.example.com.

The full key/default table lives in the Configuration reference.

Publishing the MTA-STS policy

With an [mta_sts] section configured, the service also publishes your domain’s MTA-STS policy (RFC 8461) at GET /.well-known/mta-sts.txt — the document telling sending MTAs which MX hosts may receive your mail and how strictly TLS failures must be treated. Without the section the route replies 404: publication is opt-in.

[mta_sts]
# mode = "testing"        # move to "enforce" once your MX TLS is confirmed
mx = ["mx.example.com"]   # required unless mode = "none"
# max_age = 604800        # seconds; the RFC caps it at one year

The section is validated at startup: an unknown mode, an enforce/testing policy with no mx pattern, or a max_age above the RFC’s one-year ceiling (31557600 — the value senders clamp to anyway) fails boot rather than serving a broken policy. Senders fetch the document as https://mta-sts.<domain>/.well-known/mta-sts.txt, so point an mta-sts.<domain> A (or CNAME) record at this service behind a TLS proxy holding a certificate for that hostname, and publish the _mta-sts.<domain> discovery TXT record — bumping its id whenever you edit the section. The DNS side is covered in DNS setup; the full key/default table lives in the Configuration reference.