Skip to content

Configuration reference

Generated from source for ezpds v0.12.0. Do not edit this page by hand.

Fields come from the validated Rust configuration types. Environment overrides come from the loader and are shown beside the TOML value they replace. A dash means that field has no direct environment override. Sensitive values are named but never rendered.

TOML keyEnvironment overrideRust typeSource description
bind_addressEZPDS_BIND_ADDRESSStringNo field-level description.
portEZPDS_PORT, PORTu16No field-level description.
data_dirEZPDS_DATA_DIRPathBufNo field-level description.
database_urlEZPDS_DATABASE_URLStringNo field-level description.
public_urlEZPDS_PUBLIC_URLStringNo field-level description.
service_nameEZPDS_SERVICE_NAMEStringHuman-readable display name for this instance, surfaced to end users (e.g. the resource_name field of the RFC 9728 protected-resource metadata). Distinct from telemetry.service_name (the machine-facing OTel service.name attribute). Defaults to "custos".
server_didEZPDS_SERVER_DIDOption<String>No field-level description.
available_user_domainsEZPDS_AVAILABLE_USER_DOMAINSVec<String>No field-level description.
reserved_handlesEZPDS_RESERVED_HANDLESVec<String>Handle names (the first DNS label) that may never be claimed under a served domain — infrastructure hostnames living inside the user-handle wildcard space (e.g. identitywallet, the wallet’s OAuth client_id host; about, a marketing subdomain). Compared case-insensitively against the first label. Defaults to [default_reserved_handles]; override via reserved_handles in TOML or the comma-separated EZPDS_RESERVED_HANDLES env var.
invite_code_requiredEZPDS_INVITE_CODE_REQUIREDboolNo field-level description.
linksServerLinksConfigOptional privacy-policy / terms-of-service links surfaced by com.atproto.server.describeServer.
contactContactConfigOptional admin contact surfaced by com.atproto.server.describeServer.
blobsBlobsConfigBlob storage limits and garbage-collection cadence (max blob size, per-account quota, GC interval, unreferenced-blob TTL).
blob_mirrorBlobMirrorConfigOff-volume blob replication to an S3-compatible bucket (the Litestream analogue for blob bytes). Disabled unless a bucket is configured.
blob_scrubBlobScrubConfigPeriodic blob-integrity scrub sweep (re-hash stored bytes against their CID/size, walk for orphans in both directions).
firehoseFirehoseConfigPersistent firehose event log (repo_seq) retention / pruning configuration.
accountsAccountsConfigAccount-lifecycle knobs (the scheduled-deletion reaper interval).
recoveryRecoveryConfigEscrow-assisted recovery knobs (the cancellable release-delay window).
waitlistWaitlistConfigPublic interest-signup waitlist (the waitlist capability). Off by default.
admin_devicesAdminDevicesConfigOperator companion-app admin-device knobs (the stale-nonce sweep interval and retention).
oauthOAuthConfigStub for future OAuth configuration (no fields yet).
agent_authAgentAuthConfigauth.md agent-registration knobs (per-flow enablement, issuer trust list, TTLs).
irohIrohConfigIroh QUIC networking — the peer-to-peer endpoint run alongside the HTTP server. Off by default.
notificationsNotificationsConfigPush notifications via a blind-courier relay. Off unless relay names a node id.
appviewAppViewConfigUpstream Bluesky AppView that app.bsky.* XRPC methods not served locally are proxied to (the catch-all atproto-proxy target).
chatChatConfigUpstream chat service that chat.bsky.* (direct-message) XRPC methods are proxied to; direct messages are not served locally.
crawlersCrawlersConfigCrawler (relay/BGS) com.atproto.sync.requestCrawl notification targets, pinged on new content. Defaults to the public bsky.network BGS; an empty list disables it.
labelerLabelerConfigLabeler watching: flag hosted accounts carrying labels from watched labelers.
rate_limitRateLimitConfigRequest rate-limiting knobs (global IP + per-endpoint IP + per-account write points).
telemetryTelemetryConfigTelemetry configuration: OpenTelemetry trace export, the /metrics endpoint, and the stdout log format.
emailEmailConfigOutbound email delivery (password reset, email confirmation, email update).
admin_tokenEZPDS_ADMIN_TOKENOption<Sensitive<String>>No field-level description.
signing_key_master_keyEZPDS_SIGNING_KEY_MASTER_KEYOption<Sensitive<Zeroizing<[u8; 32]>>>No field-level description.
plc_directory_urlEZPDS_PLC_DIRECTORY_URLStringNo field-level description.
links.privacy_policyOption<String>No field-level description.
links.terms_of_serviceOption<String>No field-level description.
contact.emailOption<String>No field-level description.
blobs.max_blob_sizeu64Maximum blob size in bytes. Default: 50 MiB.
blobs.max_storage_per_accountu64Per-account storage quota in bytes. Default: 1 GiB.
blobs.gc_interval_secsEZPDS_BLOBS_GC_INTERVAL_SECSu64How often the blob garbage collector runs, in seconds. Default: 1800 (30 min).
blobs.temp_ttl_secsu64Grace period, in seconds, before an unreferenced blob is deleted. Applies both to freshly uploaded blobs that are never referenced and to blobs that lose their last reference. Default: 21600 (6 hours).
blob_mirror.bucketEZPDS_BLOB_MIRROR_BUCKETOption<String>Bucket name. Setting this enables the mirror; leave unset to disable (the default).
blob_mirror.endpointEZPDS_BLOB_MIRROR_ENDPOINTOption<String>S3-compatible endpoint URL (e.g. https://t3.storage.dev). Required when bucket is set.
blob_mirror.regionEZPDS_BLOB_MIRROR_REGIONStringSigV4 signing region. S3-compatible providers commonly accept auto (the default); set the real region where the provider requires it.
blob_mirror.access_key_idEZPDS_BLOB_MIRROR_ACCESS_KEY_IDOption<String>Access key id for the bucket. Required when bucket is set.
blob_mirror.secret_access_keyEZPDS_BLOB_MIRROR_SECRET_ACCESS_KEYOption<Sensitive<String>>Secret access key for the bucket. Required when bucket is set. Wrapped in [Sensitive] so it never appears in Debug output.
blob_mirror.force_path_styleEZPDS_BLOB_MIRROR_FORCE_PATH_STYLEboolAddress the bucket as {endpoint}/{bucket}/… (path-style) instead of https://{bucket}.{endpoint-host}/… (virtual-hosted). Default false, matching the Litestream replica’s force-path-style: false for the same bucket family.
blob_mirror.key_prefixEZPDS_BLOB_MIRROR_KEY_PREFIXStringObject-key prefix the mirror owns inside the bucket. Objects under it are managed by the sweep — including deletion of keys no blobs row references — so nothing else should write there. Default: blobs/.
blob_mirror.sync_interval_secsEZPDS_BLOB_MIRROR_SYNC_INTERVAL_SECSu64How often the mirror sweep runs, in seconds. Default: 300 (5 min).
blob_scrub.interval_secsEZPDS_BLOB_SCRUB_INTERVAL_SECSu64How often the scrub sweep runs, in seconds. Default: 21600 (6 hours) — re-hashing every stored blob is I/O-heavy, so it runs far less often than the reference-reconciling blob GC.
blob_scrub.auto_healEZPDS_BLOB_SCRUB_AUTO_HEALboolWhether a bad file (hash/size mismatch, or a row whose file is missing) may be auto-healed from the blob-mirror bucket ([blob_mirror]) when it holds a verified-good copy. Default: true. Has no effect when the mirror itself is disabled — a bad file is then only ever flagged, never healed.
firehose.gc_interval_secsEZPDS_FIREHOSE_GC_INTERVAL_SECSu64How often the repo_seq retention sweep runs, in seconds. Default: 3600 (1 hour).
firehose.log_retention_secsu64Age-based retention: rows whose sequenced_at is older than this many seconds are prunable. Default: 604800 (7 days). Set to 0 to disable age-based pruning.
firehose.log_retention_countu64Count-based retention: keep at most this many of the newest rows. 0 disables count-based pruning. Default: 0 (age-based only).
accounts.deletion_reaper_interval_secsEZPDS_ACCOUNTS_DELETION_REAPER_INTERVAL_SECSu64How often the scheduled-deletion reaper runs, in seconds. The reaper permanently deletes accounts whose deleteAfter instant (recorded by com.atproto.server.deactivateAccount) has elapsed. Default: 3600 (1 hour). Must be > 0 (like the GC intervals, a zero period would panic tokio::time::interval).
accounts.child_deletion_grace_secsEZPDS_ACCOUNTS_CHILD_DELETION_GRACE_SECSu64Grace window, in seconds, between a parent scheduling a sovereign child agent’s deletion (POST /agent/child/delete) and the reaper permanently purging it. The child is deactivated immediately (so relays stop serving its repo) but the irreversible byte-purge waits this long, giving an undo window. Default: 86400 (24 hours). 0 means the next reaper tick purges. Unlike deletion_reaper_interval_secs this is not a tokio::time period, so a zero value is allowed.
accounts.password_optionalEZPDS_ACCOUNTS_PASSWORD_OPTIONALboolAllow accounts to be created with no password at all (the optionalPassword capability). Default false. When enabled, a client may omit the password field entirely at account creation and the account is stored with a NULL password_hash — authenticating thereafter through the device-key paths (wallet-confirmed OAuth consent, sovereign sessions) and through app passwords for standard ATProto clients. An empty-string password is always rejected regardless of this setting: it is indistinguishable from an uninitialized field, and creating a passwordless account from what is probably a client bug is not a guess worth making. Off by default because a passwordless account depends on device-key custody the operator cannot verify on the account holder’s behalf: a deployment whose users are not all running a wallet should keep the password required.
recovery.release_delay_secsEZPDS_RECOVERY_RELEASE_DELAY_SECSu64The cancellable delay, in seconds, between opening an escrow release (with a valid email OTP) and the Share 2 envelope becoming collectable. Default: 86400 (24 hours). 0 collapses the two-step flow to a single call that returns the share directly — appropriate only where the delay’s protection isn’t wanted (the operator’s judgment). Not a tokio::time period, so 0 is allowed.
waitlist.enabledEZPDS_WAITLIST_ENABLEDboolEnable the public waitlist signup endpoint (and advertise the waitlist capability). Default false.
admin_devices.nonce_sweep_interval_secsEZPDS_ADMIN_DEVICES_NONCE_SWEEP_INTERVAL_SECSu64How often the stale-nonce sweep runs, in seconds. Default: 3600 (1 hour). Must be > 0 (like the other periodic sweeps, a zero period would panic tokio::time::interval).
admin_devices.nonce_max_age_secsEZPDS_ADMIN_DEVICES_NONCE_MAX_AGE_SECSu64Delete nonce rows whose seen_at is older than this many seconds. Default: 3600 (1 hour) — well beyond the validated minimum of 2 * ADMIN_TIMESTAMP_WINDOW_SECS (120s), the worst-case span a captured request stays replayable after its nonce row is first inserted. Must also fit in i64 (the sweep passes it to SQLite as a signed duration).
rate_limit.enabledEZPDS_RATE_LIMIT_ENABLEDboolMaster switch. When false, the middleware and write-point checks are pure pass-throughs. Default: true.
rate_limit.global_ip_per_5minEZPDS_RATE_LIMIT_GLOBAL_IP_PER_5MINu64Global requests per IP per 5 minutes (reference: 3000). 0 disables. The global limiter exempts com.atproto.sync.getRepo and com.atproto.sync.subscribeRepos so relay backfill and firehose consumption are never throttled.
rate_limit.create_account_per_5minEZPDS_RATE_LIMIT_CREATE_ACCOUNT_PER_5MINu64com.atproto.server.createAccount requests per IP per 5 minutes (reference: 100). 0 disables.
rate_limit.create_session_per_5minEZPDS_RATE_LIMIT_CREATE_SESSION_PER_5MINu64Password or sovereign full-session creation requests per IP per 5 minutes (reference: 30). Both endpoints share one budget. 0 disables. Complements the per-identifier failed-login sliding window already applied inside the password handler.
rate_limit.reset_password_per_5minEZPDS_RATE_LIMIT_RESET_PASSWORD_PER_5MINu64com.atproto.server.resetPassword requests per IP per 5 minutes (reference: 50). 0 disables.
rate_limit.update_handle_per_5minEZPDS_RATE_LIMIT_UPDATE_HANDLE_PER_5MINu64com.atproto.identity.updateHandle requests per IP per 5 minutes (reference: 10). 0 disables.
rate_limit.transfer_accept_per_5minEZPDS_RATE_LIMIT_TRANSFER_ACCEPT_PER_5MINu64POST /v1/transfer/accept requests per IP per 5 minutes. Default 30 (in line with createSession): the endpoint authenticates on a bare 6-char transfer code, so it warrants the tight per-endpoint cap rather than only the generous global one. 0 disables.
rate_limit.agent_claim_confirm_per_5minEZPDS_RATE_LIMIT_AGENT_CLAIM_CONFIRM_PER_5MINu64POST /agent/identity/claim/confirm requests per IP per 5 minutes. Default 30: the body carries a guessable 6-digit user_code (the same short-code class as transfer/accept), so it warrants the tight per-endpoint cap even though the caller is session-authenticated. 0 disables.
rate_limit.recovery_per_5minEZPDS_RATE_LIMIT_RECOVERY_PER_5MINu64Escrow-recovery POST /v1/recovery/initiate + POST /v1/recovery/release requests per IP per 5 minutes. Default 30 (in line with createSession). The release endpoint validates an emailed OTP, so it carries the same code-guessing surface as the other short-code endpoints; initiate and release share one limiter instance so alternating between them cannot double an attacker’s OTP-guess budget (the agent claim-pair precedent). 0 disables.
rate_limit.oauth_consent_create_per_5minEZPDS_RATE_LIMIT_OAUTH_CONSENT_CREATE_PER_5MINu64Wallet-confirmed OAuth consent request creations (GET /oauth/authorize for a passwordless or migrated account) per 5 minutes. Charged in-handler against both the requesting IP and the client_id (two independent counters, one limiter), so neither a single IP nor a single client can flood the pending-request table. Default 30. 0 disables.
rate_limit.oauth_consent_action_per_5minEZPDS_RATE_LIMIT_OAUTH_CONSENT_ACTION_PER_5MINu64Wallet-consent code-validating endpoints (GET /oauth/authorize/consent-request preview + POST /oauth/authorize/approve) per IP per 5 minutes. Default 30. Preview validates a guessable user_code, so it warrants the tight per-endpoint cap (the claim confirm/preview precedent); the two share one limiter instance so alternating them can’t double the guess budget. 0 disables.
rate_limit.waitlist_per_5minEZPDS_RATE_LIMIT_WAITLIST_PER_5MINu64Public waitlist signups (POST /waitlist) per IP per 5 minutes. Default 30: the endpoint is unauthenticated and writes a row per novel email, so it warrants a tight per-endpoint cap on top of the global one. 0 disables.
rate_limit.write_points_hourlyEZPDS_RATE_LIMIT_WRITE_POINTS_HOURLYu64Repo-write points per account per hour (reference: 5000). 0 disables the hourly budget.
rate_limit.write_points_dailyEZPDS_RATE_LIMIT_WRITE_POINTS_DAILYu64Repo-write points per account per day (reference: 35000). 0 disables the daily budget.
oauth.access_token_ttl_secsEZPDS_OAUTH_ACCESS_TOKEN_TTL_SECSu64Lifetime of an OAuth access token, in seconds. Default 900 (15 minutes), matching the reference PDS: long enough that well-behaved clients are not refreshing constantly, short enough that a revocation takes effect quickly. The atproto OAuth profile recommends staying under 30 minutes, so values above that are refused rather than silently accepted. The floor exists because the conformance suite sets this to a second or two to test expiry behaviour without waiting out a real token — a legitimate use, but one worth being deliberate about, since a production instance running a 1-second token would refresh on every request.
oauth.client_jwks_cache_ttl_secsEZPDS_OAUTH_CLIENT_JWKS_CACHE_TTL_SECSu64TTL, in seconds, of a confidential client’s fetched jwks_uri document before it is re-fetched (private_key_jwt client authentication at the token endpoint). Default 3600 (1 hour) — comfortably longer than access_token_ttl_secs, so a client refreshing on its access-token TTL reuses the cached key instead of re-fetching on every refresh. Deliberately its own [crate::auth::jwks::JwksCache] instance rather than sharing [agent_auth]’s: a client’s jwks_uri is supplied by whoever registers the client, not operator-typed config.
oauth.client_jwks_refetch_cooldown_secsEZPDS_OAUTH_CLIENT_JWKS_REFETCH_COOLDOWN_SECSu64Minimum interval, in seconds, between jwks_uri fetch attempts for a given confidential client. The requesting kid comes from an unverified client_assertion header, so without this cooldown a stream of bogus-kid assertions would force one outbound fetch per token request. 0 disables the cooldown. Default 30.
agent_auth.service_auth_enabledEZPDS_AGENT_AUTH_SERVICE_AUTH_ENABLEDboolEnable the service_auth registration flow. Default false.
agent_auth.anonymous_enabledEZPDS_AGENT_AUTH_ANONYMOUS_ENABLEDboolEnable the anonymous registration flow. Default false.
agent_auth.trusted_issuersVec<TrustedIssuer>Issuers whose ID-JAGs are accepted by the identity_assertion flow. Empty (the default) means every identity_assertion request is refused with issuer_not_enabled.
agent_auth.assertion_ttl_secsEZPDS_AGENT_AUTH_ASSERTION_TTL_SECSu64Lifetime, in seconds, of a minted service identity_assertion. Default 3600 (1 hour).
agent_auth.claim_token_ttl_secsEZPDS_AGENT_AUTH_CLAIM_TOKEN_TTL_SECSu64Lifetime, in seconds, of a claim token returned for a pending claim ceremony. Default 600.
agent_auth.user_code_ttl_secsEZPDS_AGENT_AUTH_USER_CODE_TTL_SECSu64Lifetime, in seconds, of a claim ceremony’s user code. Default 600.
agent_auth.auth_time_max_age_secsEZPDS_AGENT_AUTH_AUTH_TIME_MAX_AGE_SECSu64Maximum age, in seconds, of an ID-JAG’s auth_time before the flow returns login_required (the assertion is too stale to trust). Default 3600 (1 hour).
agent_auth.granted_scopesVec<String>Scopes granted to a fully-registered agent identity. Defaults to a conservative granular profile — write-to-own-repo plus blob uploads, with AppView reads reaching the agent through the read-proxy (which any access-level token may use). See default_agent_granted_scopes. Operator warning: these are enforced through the same granular scope grammar as OAuth tokens (auth/oauth_scopes.rs), so an agent token can only do what these scopes permit. Do not add account:* or identity:* (or the legacy com.atproto.access full-access scope, or transition:generic) unless you intend agents to change account settings, rotate handles/PLC identity, or otherwise hold account-lifecycle control — that hands an agent the same reach as the account owner’s own wallet.
agent_auth.pre_claim_scopesVec<String>Scopes carried by a pre-claim (anonymous) assertion. Defaults to the same conservative profile as granted_scopes.
agent_auth.verification_uriEZPDS_AGENT_AUTH_VERIFICATION_URIOption<String>The human-facing URL where a user enters the claim-ceremony user_code. When None (the default) the handler derives {public_url}/agent/claim.
agent_auth.claim_sweep_interval_secsEZPDS_AGENT_CLAIM_SWEEP_INTERVAL_SECSu64How often the claim-attempt expiry sweep runs, in seconds. Default: 300 (5 minutes — the user-code TTL is 600, so a lapsed ceremony is marked expired within half its window). Must be > 0 (like the GC intervals, a zero period would panic tokio::time::interval).
agent_auth.jwks_cache_ttl_secsEZPDS_AGENT_AUTH_JWKS_CACHE_TTL_SECSu64TTL, in seconds, of a fetched issuer JWKS before it is re-fetched (dynamic jwks_url trust). A rotated key whose kid isn’t in the cached set triggers a re-fetch as soon as jwks_refetch_cooldown_secs allows, so this only bounds how long a removed key stays trusted. Default 3600 (1 hour).
agent_auth.jwks_refetch_cooldown_secsEZPDS_AGENT_AUTH_JWKS_REFETCH_COOLDOWN_SECSu64Minimum interval, in seconds, between JWKS fetch attempts for a given jwks_url. The requesting kid comes from an unverified JWT header on public endpoints, so without this cooldown a stream of bogus-kid tokens would force one outbound fetch per request. Within the cooldown an unknown kid resolves against the last fetched set and a failed fetch keeps failing fast; a genuine key rotation is picked up after at most one cooldown. Should stay well below jwks_cache_ttl_secs. 0 disables the cooldown. Default 30.
iroh.enabledEZPDS_IROH_ENABLEDboolWhether to run the Iroh QUIC endpoint alongside the HTTP server. Off by default, so a relay (and the test suite) behaves exactly as before unless explicitly enabled.
iroh.endpointEZPDS_IROH_ENDPOINTOption<String>Optional manual override for the advertised node id. When None (the default), the pds advertises its live endpoint’s node id (present only while the tunnel is enabled); when set, this exact string is advertised instead. The override is read straight from config by the handler, so it applies even when enabled is false (i.e. with no live endpoint running).
iroh.ipv6EZPDS_IROH_IPV6boolWhether to bind the IPv6 QUIC socket. Defaults to true. Set to false on hosts with no public IPv6 egress (e.g. Railway containers, which carry internal v6 addresses but can’t route them): iroh’s v6 relay probes would otherwise fail with NetworkUnreachable forever, one WARN every ~80s, drowning real errors. IPv4 paths carry all traffic either way — this only skips the doomed v6 socket.
notifications.relayEZPDS_NOTIFICATIONS_RELAYOption<String>The relay’s iroh node id. None disables notifications entirely.
notifications.enrollment_codeEZPDS_NOTIFICATIONS_ENROLLMENT_CODEOption<Sensitive<String>>Single-use enrollment grant for a relay that gates enrollment (the official one does; a self-run relay may set open_enrollment instead). Consumed by the relay on the first successful enroll; harmless to leave configured afterwards, since enrollment is idempotent for an already-enrolled node. [Sensitive] because it is a bearer grant: anyone holding it can enroll a node of their choosing with the relay.
appview.urlEZPDS_APPVIEW_URLStringBase URL of the AppView (scheme + authority, no trailing slash).
appview.didEZPDS_APPVIEW_DIDStringService DID (with #fragment) of the AppView, sent as atproto-proxy.
appview.cdn_urlEZPDS_APPVIEW_CDN_URLStringBase URL of the AppView’s image CDN (scheme + authority, no trailing slash), used to build avatar/banner/embed-image URLs for the account’s own not-yet-indexed records. Defaults to Bluesky’s public image CDN.
chat.urlEZPDS_CHAT_URLStringBase URL of the chat service (scheme + authority, no trailing slash).
chat.didEZPDS_CHAT_DIDStringService DID (with #fragment) of the chat service, sent as atproto-proxy.
crawlers.urlsEZPDS_CRAWLERSVec<String>No field-level description.
labeler.watchedEZPDS_LABELER_WATCHEDVec<WatchedLabeler>Labelers whose account-level labels flag hosted accounts. Empty (the default) disables labeler watching entirely.
labeler.poll_interval_secsEZPDS_LABELER_POLL_INTERVAL_SECSu64How often the watcher polls each watched labeler’s com.atproto.label.queryLabels, in seconds. Default: 900 (15 minutes). Must be > 0 (like the GC intervals, a zero period would panic tokio::time::interval).
telemetry.enabledEZPDS_TELEMETRY_ENABLEDboolWhether to export traces via OTLP. Off by default — zero overhead when disabled.
telemetry.otlp_endpointEZPDS_OTLP_ENDPOINTStringOTLP gRPC endpoint for the trace exporter.
telemetry.service_nameOTEL_SERVICE_NAMEStringservice.name resource attribute reported to the trace backend.
telemetry.metrics_enabledEZPDS_METRICS_ENABLEDboolWhether to register the metrics meter and serve GET /metrics. On by default; when off, no meter is registered and the route returns 404.
telemetry.metrics_require_adminEZPDS_METRICS_REQUIRE_ADMINboolRequire admin auth on GET /metrics. Off by default so a plain Prometheus scraper works; operators exposing the endpoint beyond a private network can turn it on.
telemetry.log_formatEZPDS_LOG_FORMATLogFormatEncoding of the stdout log stream (independent of OTLP export).
email.providerEZPDS_EMAIL_PROVIDEREmailProviderNo field-level description.
email.fromEZPDS_EMAIL_FROMOption<String>From address on every message (e.g. noreply@pds.example.com). Required for SMTP.
email.from_nameEZPDS_EMAIL_FROM_NAMEOption<String>Optional display name paired with from (e.g. Custos PDS).
email.smtp_hostEZPDS_EMAIL_SMTP_HOSTOption<String>SMTP relay host. Required when provider = "smtp".
email.smtp_portEZPDS_EMAIL_SMTP_PORTu16SMTP relay port. Default 587 (STARTTLS submission).
email.smtp_usernameEZPDS_EMAIL_SMTP_USERNAMEOption<String>SMTP AUTH username. When set (with a password), the sender authenticates.
email.smtp_passwordEZPDS_EMAIL_SMTP_PASSWORDOption<Sensitive<String>>SMTP AUTH password. Wrapped in [Sensitive] so it never appears in Debug output.
email.smtp_tlsEZPDS_EMAIL_SMTP_TLSSmtpTlsTransport security mode.
email.smtp_timeout_secsEZPDS_EMAIL_SMTP_TIMEOUT_SECSu64Connect/send timeout for the SMTP transport, in seconds. send() is awaited on the request path, so this bounds how long a slow or unresponsive relay can stall a handler. Default 15.
email.http_tokenEZPDS_EMAIL_HTTP_TOKENOption<Sensitive<String>>HTTP-API bearer token (e.g. the Mailtrap API token). Required when provider = "mailtrap". Wrapped in [Sensitive] so it never appears in Debug output, like smtp_password.
email.http_api_urlEZPDS_EMAIL_HTTP_API_URLOption<String>HTTP-API send endpoint. Defaults to the provider’s production endpoint (https://send.api.mailtrap.io/api/send for Mailtrap) when unset; overridable so tests can point at a local mock server.
email.http_timeout_secsEZPDS_EMAIL_HTTP_TIMEOUT_SECSu64Request timeout for the HTTP-API sender, in seconds. Bounds how long a slow or unresponsive email API can stall a handler (the smtp_timeout_secs precedent for the HTTPS path). Default 15.
  • EZPDS_CONFIG — path to the TOML configuration file (CLI source).