Skip to main content
Version: Dev

Configure Email (SMTP)

The On-Premises control plane can send email through an SMTP relay that you operate or subscribe to. cp-api is the only component that sends email, and it uses the relay for four messages:

  • Invitation emails. When an administrator invites a member, the invitation link is emailed to the invitee. See Invite a Member.
  • Password reset emails. A user who forgot their password can request a reset link from the sign-in page. See Reset a Forgotten Password.
  • Set-password emails. When an administrator enables sign-in for a member or resets a member's password, the one-time link is emailed to the member. See Enable Sign-In or Reset a Password.
  • A test email. An organization administrator can send a test message to their own address to check the relay.

Email is off until you set the relay host. Without it, the dashboard shows each invitation and set-password link for the administrator to pass on by hand, and the forgot-password page tells users to contact their administrator.

Settings​

Configure the relay with Helm values or, for a Docker Compose installation, in ./aisix-self-hosted/.env:

Helm valueDocker Compose variablePurpose
api.smtp.hostAISIX_CLOUD_SMTP_HOSTRelay host name. Empty, the default, turns email off.
api.smtp.tlsAISIX_CLOUD_SMTP_TLSHow the connection is protected: starttls (the default), smtps, or none. See Connection Security.
api.smtp.portAISIX_CLOUD_SMTP_PORTRelay port. When unset, the port follows the TLS mode: 587 for starttls, 465 for smtps, and 25 for none.
api.smtp.fromAISIX_CLOUD_SMTP_FROMSender address of every email, such as AISIX <noreply@example.com>. Required when the host is set.
api.smtp.usernameAISIX_CLOUD_SMTP_USERNAMEUsername for SMTP authentication. Optional; see Authentication.
api.smtp.password, or api.smtp.existingSecret and api.smtp.existingSecretKeyAISIX_CLOUD_SMTP_PASSWORDPassword for SMTP authentication. The chart stores api.smtp.password in its own Secret, or reads the key named by api.smtp.existingSecretKey (smtp-password by default) from an existing Secret.
api.smtp.invitationLimitPerHourAISIX_CLOUD_SMTP_INVITATION_LIMIT_PER_HOURMost invitation emails one account may send per rolling hour. 50 by default. See Invitation Email Limit.

In the cp-api configuration file these settings are the smtp group: smtp.host, smtp.port, smtp.tls, smtp.from, smtp.username, and smtp.invitation_limit_per_hour. The password is never read from the configuration file. It reaches cp-api only through the AISIX_CLOUD_SMTP_PASSWORD environment variable, which the chart fills from a Secret.

cp-api checks the settings at startup and refuses to start, naming the setting, when the host is set and:

  • from is missing or is not a valid email address;
  • only one of the username and the password is set;
  • the TLS mode is not one of starttls, smtps, or none; or
  • the port is outside 1–65535.

cp-api also refuses to start, even with email off, when the port is not a number or the invitation limit is not a whole number of at least 1.

A misconfigured relay therefore stops the control plane at startup rather than failing the first invitation.

Helm​

With a relay that requires authentication, keep the password in a Secret you manage:

kubectl create secret generic aisix-smtp \
--namespace aisix-cp --from-literal=smtp-password='YOUR_SMTP_PASSWORD'
values.yaml
api:
smtp:
host: smtp.example.com
from: "AISIX <noreply@example.com>"
username: aisix-notifications
existingSecret: aisix-smtp

Apply the values with helm upgrade. A change to the api.smtp values rolls the cp-api pods.

Docker Compose​

Add the settings to ./aisix-self-hosted/.env:

AISIX_CLOUD_SMTP_HOST=smtp.example.com
AISIX_CLOUD_SMTP_FROM="AISIX <noreply@example.com>"
AISIX_CLOUD_SMTP_USERNAME=aisix-notifications
AISIX_CLOUD_SMTP_PASSWORD=YOUR_SMTP_PASSWORD

Then recreate cp-api from the ./aisix-self-hosted directory:

docker compose up -d api

Authentication​

Set both the username and the password to authenticate to the relay. cp-api then uses the PLAIN mechanism, or LOGIN when the relay offers only that.

Leave both empty to send without authenticating, for example through an internal relay that accepts mail from the control plane's IP addresses. cp-api then never authenticates, even when the relay advertises authentication:

values.yaml
api:
smtp:
host: mail-relay.internal.example.com
from: "AISIX <noreply@example.com>"

Setting only one of the two is refused at startup.

Connection Security​

ModeBehavior
starttlsConnects in plain text and upgrades the connection with STARTTLS. If the relay does not offer STARTTLS, delivery fails instead of continuing in plain text.
smtpsUses TLS from the first byte, usually on port 465.
noneNever encrypts the connection and never attempts STARTTLS.

In starttls and smtps mode, cp-api always verifies the relay's certificate against the system trust store of the cp-api image. There is no setting to skip verification or supply a custom CA.

caution

With none, every email crosses the network in plain text, including the invitation and password reset links it carries. If a username and password are set, they cross the network in plain text too, and cp-api logs a warning at startup. Use none only for a relay on a trusted internal network.

Invitation Email Limit​

While email is on, each inviting account may send at most api.smtp.invitationLimitPerHour invitation emails per rolling hour, 50 by default. The count covers every organization the account belongs to, and creating and resending an invitation both count. A request over the limit is refused with 429 and a Retry-After header, and no invitation is created or reissued. The count is kept in the database, so it holds across cp-api replicas. The limit cannot be turned off; the lowest value is 1.

Keep this limit in place. Every member who can invite can send email to arbitrary addresses through your relay, and the limit is what caps how much.

With email off, nothing is sent and nothing is counted.

Email Language​

Emails are written in the deployment's language, the same one the dashboard uses: ui.defaultLocale in Helm, or AISIX_DASHBOARD_LOCALE in Docker Compose. Supported values are en and zh. In the cp-api configuration file the setting is i18n.default_locale, and the AISIX_CLOUD_DEFAULT_LOCALE variable overrides it. See Dashboard Language.

Send a Test Email​

After the relay is configured, verify it from the dashboard:

  1. Sign in as an organization owner or administrator and open Settings.
  2. In the Email (SMTP) card, check the status. When the relay is configured, the card shows its host, port, TLS mode, and sender address. It never shows the credentials.
  3. Select Send test email. The message goes to your own account's address.

If the relay does not accept the message, the card reports which step failed:

FailureMeaning
Connectioncp-api could not reach the relay: a DNS failure, a refused or dropped connection, or a timeout.
TLSThe TLS handshake or certificate check failed, or the relay does not offer STARTTLS in starttls mode.
AuthenticationThe relay rejected the configured credentials, or offers no mechanism cp-api can use.
RejectedThe relay refused the message. The card shows the SMTP reply code and message.

The same classification is shown on an invitation whose email was not delivered. Each client address can send five test emails per minute.

Rate Limits Behind a Reverse Proxy​

Sign-in, sign-up, password reset, and the test email are rate-limited per client address. By default, cp-api treats the address of whatever connected to it as the client. Behind an ingress controller or load balancer, that is the proxy, so every user shares one rate-limit budget, and a burst of requests from one user can refuse the others.

To use the real client address, list the proxies in front of cp-api as CIDRs in api.trustedProxies, or as a comma-separated AISIX_TRUSTED_PROXIES value in Docker Compose. cp-api then walks the X-Forwarded-For header from the right, skips every address inside a listed range, and uses the first one outside as the client. List only proxies you run: a listed range can claim any client address.

values.yaml
api:
trustedProxies:
- 10.0.0.0/8

Next Steps​

See Members for how invitations and password resets behave for users, and On-Premises Configuration for the other control-plane settings.