114 lines
5.8 KiB
Markdown
114 lines
5.8 KiB
Markdown
# 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.
|