SMTP Configuration
Self-Hosted Deployments Only
This guide is for Self-Hosted deployments. Managed customers do not configure SMTP — Qualytics operates the email transport on your behalf.
This guide explains how to configure outbound email delivery for a Self-Hosted Qualytics deployment. The controlplane uses SMTP to send user invitations, password resets, scheduled report deliveries, and operational notifications. Without SMTP configured, those email-driven flows are disabled but the rest of the platform continues to function.
How it works
Two Helm value groups configure SMTP:
| Group | Purpose | Where it lives in values.yaml |
|---|---|---|
controlplane.smtp |
Connection settings (server, port, sender, enable toggle) | Controlplane block |
secrets.smtp |
Credentials (username, password) — optional for relays that allow anonymous auth | Secrets block, injected as a Kubernetes secret |
When controlplane.smtp.enabled is true, the chart injects SMTP_SERVER, SMTP_PORT, and SMTP_SENDER_EMAIL into the controlplane API and worker pods. If both secrets.smtp.smtp_sender_user and secrets.smtp.smtp_sender_password are non-empty, SMTP_SENDER_USER and SMTP_SENDER_PASSWORD are also injected from a Kubernetes secret. If either credential is empty, the controlplane connects without authentication — useful for trusted internal relays.
Required configuration
Add the following to your values.yaml (or your chart overrides):
controlplane:
smtp:
enabled: true
server: "smtp.example.com"
port: "465"
sender: "no-reply@your-company.com"
secrets:
smtp:
smtp_sender_user: "your-smtp-username"
smtp_sender_password: "your-smtp-password"
| Field | Description |
|---|---|
controlplane.smtp.enabled |
Master toggle. Set to false to disable SMTP entirely. |
controlplane.smtp.server |
SMTP host. Examples: email-smtp.us-east-1.amazonaws.com (AWS SES), smtp.gmail.com, smtp.office365.com, or your internal relay. |
controlplane.smtp.port |
SMTP port as a string. Use 465 for implicit TLS (SMTPS), 587 for STARTTLS, or 25 for unencrypted internal relays. |
controlplane.smtp.sender |
The From address shown on outgoing emails. Must be a sender your SMTP provider has authorized. |
secrets.smtp.smtp_sender_user |
SMTP username. Leave empty for anonymous (no-auth) relays. |
secrets.smtp.smtp_sender_password |
SMTP password or provider-specific access token. Leave empty for anonymous relays. |
Sender address must be authorized
Most SMTP providers (AWS SES, Gmail, Office 365) reject mail when the From address is not a verified or authorized sender on the account. Verify your sender value with your provider before deploying.
Common providers
controlplane:
smtp:
enabled: true
server: "email-smtp.us-east-1.amazonaws.com"
port: "465"
sender: "no-reply@your-verified-domain.com"
secrets:
smtp:
smtp_sender_user: "<SES_SMTP_USERNAME>"
smtp_sender_password: "<SES_SMTP_PASSWORD>"
SES SMTP credentials are not the same as your AWS access keys — generate them from the SES console under SMTP settings → Create SMTP credentials. The sender domain or address must be verified in SES, and your account must be moved out of the SES sandbox to email arbitrary recipients.
controlplane:
smtp:
enabled: true
server: "smtp.gmail.com"
port: "465"
sender: "no-reply@your-workspace-domain.com"
secrets:
smtp:
smtp_sender_user: "no-reply@your-workspace-domain.com"
smtp_sender_password: "<APP_PASSWORD>"
Use a Google App Password — regular account passwords will not work. The account must have 2-Step Verification enabled.
controlplane:
smtp:
enabled: true
server: "smtp.office365.com"
port: "587"
sender: "no-reply@your-tenant.onmicrosoft.com"
secrets:
smtp:
smtp_sender_user: "no-reply@your-tenant.onmicrosoft.com"
smtp_sender_password: "<APP_PASSWORD>"
Office 365 requires STARTTLS on port 587. SMTP AUTH must be enabled on the mailbox, which Microsoft disables by default for tenants created after 2020 — your administrator may need to re-enable it via PowerShell.
controlplane:
smtp:
enabled: true
server: "internal-relay.your-company.local"
port: "25"
sender: "no-reply@your-company.com"
secrets:
smtp:
smtp_sender_user: ""
smtp_sender_password: ""
Leaving both credential fields empty causes the chart to skip injecting SMTP_SENDER_USER / SMTP_SENDER_PASSWORD, and the controlplane connects without authentication. Use this for internal MTAs that authorize the controlplane pods by source IP or network position.
TLS certificate validation
The controlplane validates TLS certificates on outbound SMTP SSL sessions by default. If your relay uses a private CA or self-signed certificate (common in air-gapped environments), disable validation globally:
This setting also disables validation for HTTP egress and other outbound TLS sessions, so prefer importing your private CA into the controlplane image when possible.
Apply and verify
Apply your changes with helm upgrade:
Restart the controlplane pods to pick up the new env vars:
Verify the env vars landed in the controlplane:
Expected output (the password is intentionally not echoed by the controlplane image but the env var should be set):
SMTP_SERVER=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=465
SMTP_SENDER_EMAIL=no-reply@your-domain.com
SMTP_SENDER_USER=AKIA...
SMTP_SENDER_PASSWORD=********
To exercise the live SMTP path, invite a test user from the Settings → Users screen and confirm the invitation email arrives.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| No emails sent, no errors in logs | controlplane.smtp.enabled is false, or env vars are missing because the deployment was not restarted |
Confirm enabled: true, run kubectl rollout restart, and re-check env vars. |
SMTPAuthenticationError |
Wrong username/password, or the provider requires an app-specific password / SES SMTP credential | Regenerate credentials with the provider and update secrets.smtp. |
SMTPSenderRefused |
sender is not a verified address on the provider account |
Verify the sender address with your provider; for SES, check the SES sandbox status. |
SSLError / CertificateVerifyFailed |
Relay uses a private CA the controlplane does not trust | Either import the CA into the controlplane image or set controlplane.egress.verifyTLSCertificates: false. |
| Connection timeout | NetworkPolicy or egress firewall blocks outbound SMTP | Allow egress from the controlplane namespace to the SMTP host on the configured port. |
Connection unexpectedly closed on port 587 |
Relay requires STARTTLS but is being approached as implicit TLS | Confirm port matches the provider's auth mode — 465 for SMTPS, 587 for STARTTLS. |