Deploy and operate
Documentation

Version Latest

Email

Configure the SMTP server Govern sends verification, password reset, magic link and email change notices through, and know at once when delivery fails.

Govern sends verification, password reset, magic link and email change notices through one SMTP server. Without one (NI_AUTH_SMTP_HOST empty), nothing is sent and the request that needs mail answers 503 email_unavailable.

Settings

VariableMeaning
NI_AUTH_SMTP_HOSTMail server host name. Empty: delivery is off (logged at start). localhost works only when a mail server listens on the Govern host or container
NI_AUTH_SMTP_PORTPort, default 587
NI_AUTH_SMTP_STARTTLStrue (the server's default): require STARTTLS before authenticating; a server without it is refused
NI_AUTH_SMTP_USERNAME, NI_AUTH_SMTP_PASSWORDSMTP credentials (PLAIN, only over TLS or to localhost). Keep them in your secret store
NI_AUTH_SMTP_FROMThe From address; its domain must be one your provider lets you send from
NI_AUTH_SMTP_INSECURE_SKIP_VERIFYNever in production
NI_AUTH_SIGN_IN_URLWhere the "Sign in" button of the email link pages points (https); empty: no button

The Docker Compose stack points at its Mailpit container by default (NI_AUTH_SMTP_HOST=mailpit, port 1025, STARTTLS off), which captures mail for local development at http://localhost:8025. Set real values for any other use.

Example: Amazon SES

  1. In the SES console of the region you send from, verify the domain of NI_AUTH_SMTP_FROM (DKIM records; add SPF and DMARC for deliverability).

  2. Request production access: in the SES sandbox only verified addresses receive mail, and others are refused (reason=rejected).

  3. Create SMTP credentials in the SES console. They are an SMTP user name and password, not IAM access keys.

  4. Configure Govern:

    NI_AUTH_SMTP_HOST=email-smtp.eu-west-1.amazonaws.com
    NI_AUTH_SMTP_PORT=587
    NI_AUTH_SMTP_STARTTLS=true
    NI_AUTH_SMTP_USERNAME=<SES SMTP user name>
    NI_AUTH_SMTP_PASSWORD=<SES SMTP password>
    NI_AUTH_SMTP_FROM=no-reply@<verified domain>
  5. Restart, then probe as a super admin: POST /api/v1/admin/email/probe must answer status: ok. Request a verification email for a test account.

Outbound TCP 587 to the SES endpoint must be allowed. In an air-gapped installation, point NI_AUTH_SMTP_HOST at your internal relay.

Knowing whether mail works

  • Logs. Every failed send is logged at error level with event=email_delivery_failed, a reason and a hint. Reasons: not_configured, connect, timeout, tls, auth, rejected (a 5xx, for example an unverified sender), temporary (a 4xx), circuit_open (sends paused after repeated failures), other. The recipient is logged by domain only.
  • Probe. The mail server is probed at start and every 5 minutes: connect, STARTTLS, authenticate, quit. Nothing is sent.
  • Metrics on /metrics: keystone_email_deliveries_total{kind="send|probe",result="sent|failed",reason} and keystone_email_delivery_healthy (1 or 0). Alert on keystone_email_delivery_healthy == 0 for 10 minutes.
  • Readiness. GET /readyz includes "email": "ok" | "failing" | "unconfigured" | "unknown". It never makes the node unready.
  • Admin view. GET /api/v1/admin/email/health (super admins) returns the status, host, port, STARTTLS, From, whether credentials are set, the last success and failure times, the last reason and the number of consecutive failures. POST /api/v1/admin/email/probe probes now and returns the same object; use it after a configuration change.
  • Circuit breaker. Selfguard guards the mail server with the smtp breaker: an outage fails fast instead of holding requests, and a rejected recipient does not count as an outage. An open breaker raises a dependency.breaker_open finding; it closes by itself once a trial send succeeds.

Last reviewed 17 October 2026View as Markdown

Email · Docs · Neural Inverse