# SMTP Configuration – Concept **Status:** Implemented **Last updated:** 2026-03-12 --- ## 1. Goal Enable configurable SMTP for sending transactional emails (join confirmation, user confirmation, password reset). Configuration via **environment variables** and **Admin Settings** (database), with the same precedence pattern as OIDC and Vereinfacht: **ENV overrides Settings**. Include a **test email** action in Settings (button + recipient field) with clear success/error feedback. --- ## 2. Scope - **In scope:** SMTP server configuration (host, port, credentials, TLS/SSL), sender identity (from-name, from-email), test email from Settings UI, warning when SMTP is not configured in production, specific error messages per failure category, graceful delivery errors in AshAuthentication senders. - **Out of scope:** Separate adapters per email type; retry queues. --- ## 3. Configuration Sources | Source | Priority | Use case | |----------|----------|-----------------------------------| | ENV | 1 | Production, Docker, 12-factor | | Settings | 2 | Admin UI, dev without ENV | When an ENV variable is set, the corresponding Settings field is read-only in the UI (with hint "Set by environment"). --- ## 4. SMTP Parameters | Parameter | ENV | Settings attribute | Notes | |----------------|------------------------|---------------------|---------------------------------------------| | Host | `SMTP_HOST` | `smtp_host` | e.g. `smtp.example.com` | | Port | `SMTP_PORT` | `smtp_port` | Default 587 (TLS), 465 (SSL), 25 (plain) | | Username | `SMTP_USERNAME` | `smtp_username` | Optional if no auth | | Password | `SMTP_PASSWORD` | `smtp_password` | Sensitive, not shown when set | | Password file | `SMTP_PASSWORD_FILE` | — | Docker/Secrets: path to file with password | | TLS/SSL | `SMTP_SSL` | `smtp_ssl` | `tls` / `ssl` / `none` (default: tls) | | Sender name | `MAIL_FROM_NAME` | `smtp_from_name` | Display name in "From" header (default: Mila)| | Sender email | `MAIL_FROM_EMAIL` | `smtp_from_email` | Address in "From" header; must match SMTP user on most servers | **Important:** On most SMTP servers (e.g. Postfix with strict relay policies) the sender email (`smtp_from_email`) must be the same address as `smtp_username` or an alias that is owned by that account. --- ## 5. Password from File Support **SMTP_PASSWORD_FILE** (path to file containing the password), same pattern as `OIDC_CLIENT_SECRET_FILE` in `runtime.exs`. Read once at runtime; `SMTP_PASSWORD` ENV overrides file if both are set. --- ## 6. Behaviour When SMTP Is Not Configured - **Dev/Test:** Keep current adapters (`Swoosh.Adapters.Local`, `Swoosh.Adapters.Test`). No change. - **Production:** If neither ENV nor Settings provide SMTP (no host): - Show a warning in the Settings UI. - Delivery attempts silently fall back to the Local adapter (no crash). --- ## 7. Test Email (Settings UI) - **Location:** SMTP / E-Mail section in Global Settings. - **Elements:** Input for recipient, submit button inside a `phx-submit` form. - **Behaviour:** Sends one email using current SMTP config and `mail_from/0`. Returns `{:ok, _}` or `{:error, classified_reason}`. - **Error categories:** `:sender_rejected`, `:auth_failed`, `:recipient_rejected`, `:tls_failed`, `:connection_failed`, `{:smtp_error, message}` — each shows a specific human-readable message in the UI. - **Permission:** Reuses existing Settings page authorization (admin). --- ## 8. Sender Identity (`mail_from`) `Mv.Mailer.mail_from/0` returns `{name, email}`. Priority: 1. `MAIL_FROM_NAME` / `MAIL_FROM_EMAIL` ENV variables 2. `smtp_from_name` / `smtp_from_email` in Settings (DB) 3. Hardcoded defaults: `{"Mila", "noreply@example.com"}` Provided by `Mv.Config.mail_from_name/0` and `Mv.Config.mail_from_email/0`. --- ## 9. AshAuthentication Senders Both `SendPasswordResetEmail` and `SendNewUserConfirmationEmail` use `Mv.Mailer.deliver/1` (not `deliver!/1`). Delivery failures are logged (`Logger.error`) and not re-raised, so they never crash the caller process. AshAuthentication ignores the return value of `send/3`. --- ## 10. TLS / SSL in OTP 27 OTP 26+ enforces `verify_peer` by default, which fails for self-signed or internal SMTP server certificates. Both `tls_options: [verify: :verify_none]` (for STARTTLS, port 587) and `sockopts: [verify: :verify_none]` (for direct SSL, port 465) are set in `Mv.Mailer.smtp_config/0` to allow such certificates. For ENV-based boot config, the same options are set in `config/runtime.exs`. --- ## 11. Summary Checklist - [x] ENV: `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_PASSWORD_FILE`, `SMTP_SSL`. - [x] ENV: `MAIL_FROM_NAME`, `MAIL_FROM_EMAIL` for sender identity. - [x] Settings: attributes and UI for host, port, username, password, TLS/SSL, from-name, from-email. - [x] Password from file: `SMTP_PASSWORD_FILE` supported in `runtime.exs`. - [x] Mailer: Swoosh SMTP adapter configured from merged ENV + Settings when SMTP is configured. - [x] Per-request SMTP config via `Mv.Mailer.smtp_config/0` for Settings-only scenarios. - [x] TLS certificate validation relaxed for OTP 27 (tls_options + sockopts). - [x] Prod warning: clear message in Settings when SMTP is not configured. - [x] Test email: form with recipient field, translatable content, classified success/error messages. - [x] AshAuthentication senders: graceful error handling (no crash on delivery failure). - [x] Gettext for all new UI strings, translated to German. - [x] Docs and code guidelines updated.