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_fileconfigured,POST /domainreplies 503 — DNS verification lookups still work, but on-chain authorization is disabled until a delegate key is set.delegate_key_fileis 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 everyPOST /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):
| Route | Method | Client | Purpose |
|---|---|---|---|
/.well-known/autoconfig/mail/config-v1.1.xml | GET | Thunderbird | Mozilla autoconfig, served from the mail domain itself |
/mail/config-v1.1.xml | GET | Thunderbird | The 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.xml | POST | Outlook | Plain-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-table | host default | port default | socket_type default |
|---|---|---|---|
[mail_hosts.imap] | 127.0.0.1 | 993 | SSL |
[mail_hosts.pop] | 127.0.0.1 | 995 | SSL |
[mail_hosts.smtp] | 127.0.0.1 | 465 | SSL |
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.