add smtp mailer settings #470

Merged
simon merged 5 commits from feature/308-web-form into main 2026-03-12 15:59:01 +01:00
Owner

Description of the implemented changes

The changes were:

  • Bugfixing
  • New Feature
  • Breaking Change
  • Refactoring

Goal: Add a configurable public join flow (double opt-in, join requests) and admin approval UI, plus configurable SMTP for transactional emails (join confirmation, password reset, etc.) with a test-email action in Global Settings.


What has been changed?

Public join flow & join requests

  • Public join page (/join): Unauthenticated form; admin-configurable fields (member + custom); submit creates a JoinRequest in status pending_confirmation; confirmation email with link; after link click, status becomes submitted. See docs/onboarding-join-concept.md.
  • JoinRequest resource (Ash): Status flow, confirmation token (hashed in DB), form data filtered by allowlist; changes for confirm, approve, reject, and join-form field normalization.
  • Join confirmation email (Swoosh): Layout and template; sent on submit; uses Mv.Mailer and mail_from/0.
  • Rate limiting for join submissions (MvWeb.JoinRateLimit).
  • Cleanup task mix join_requests.cleanup_expired for expired confirmation tokens.
  • Plugs: JoinFormEnabled (only when join form is enabled in settings); CheckPagePermission updated for new routes.
  • Router: Public /join, confirm route, and (admin) join-request list/show routes.

Admin: join request approval UI

  • Join request list (LiveView): Filter by status; links to show.
  • Join request show: Display form data; Approve and Reject actions with optional reason; policies so only users with join-request access can approve/reject.
  • Sidebar: Entry for “Join requests” when permitted.

SMTP configuration (Global Settings)

  • Settings (DB): New attributes for SMTP (host, port, username, password, TLS/SSL) and sender identity (smtp_from_name, smtp_from_email). ENV overrides Settings (same pattern as OIDC/Vereinfacht). See docs/smtp-configuration-concept.md.
  • Mv.Config: Helpers smtp_*, mail_from_name/0, mail_from_email/0, and *_env_set?/0; password from ENV, SMTP_PASSWORD_FILE, or Settings (sensitive).
  • Mv.Mailer: Swoosh mailer; mail_from/0 from ENV or Settings; send_test_email/1 with classified errors (:sender_rejected, :auth_failed, :tls_failed, etc.); smtp_config/0 for Settings-only SMTP; TLS options for OTP 27 (e.g. self-signed certs).
  • Global Settings UI: SMTP section with host/port/username/password/TLS/SSL and sender name/email; hint that sender email should match SMTP user; “Test email” form with recipient input and success/error messages; production warning when SMTP is not configured.
  • AshAuthentication senders (password reset, user confirmation): Use deliver/1 instead of deliver!/1; log delivery failures, do not crash caller.
  • Migrations: SMTP columns and smtp_from_name / smtp_from_email on settings table.

Other

  • Member index: Filter component and URL param handling (e.g. filter state in URL).
  • Email layout: Shared layout and templates for transactional emails (join confirmation, password reset, user confirmation).
  • Docs: docs/smtp-configuration-concept.md, docs/onboarding-join-concept.md; updates to CODE_GUIDELINES.md (Email §3.11, Gettext merge workflow in §3.12), docs/feature-roadmap.md, docs/page-permission-route-coverage.md, development log.
  • Gettext: New and updated strings; DE translations for new UI and SMTP messages.
  • Config: runtime.exs SMTP and mail_from from ENV; test.exs mailer adapter; release/docker-entrypoint and Drone adjustments as needed.

Definition of Done

Code Quality

  • No new technical depths
  • Linting passed
  • Documentation is added where needed (concept docs, CODE_GUIDELINES, inline where useful)

Accessibility

  • New elements are properly defined with html-tags
  • Colour contrast follows WCAG criteria
  • Aria labels are added when needed (review: join form, approval UI, SMTP test section)
  • Everything is accessible by keyboard
  • Tab-Order is comprehensible (review: join form and approval modals)
  • All interactive elements have a visible focus (review: custom buttons/links in new LiveViews)

Testing

  • Tests for new code are written (join requests, join flow, approval, SMTP config, mailer, global settings SMTP section)
  • All tests pass
  • axe-core dev tools show no critical or major issues (please run on /join and join-request list/show)

Additional Notes

  • Review focus: Join flow (allowlist, token handling, rate limit), approval policies and who can approve/reject, SMTP precedence (ENV vs Settings) and test-email error handling, and that no secrets (e.g. SMTP password) are exposed in UI or logs.
  • Config: In production, set MAIL_FROM_EMAIL (and optionally MAIL_FROM_NAME) to match the SMTP user if using ENV; otherwise configure “Sender email (From)” in Global Settings. Sender address must usually match the SMTP account to avoid 553 rejections.
  • Gettext: After merging, run mix gettext.extract --merge if new strings were added on main; see CODE_GUIDELINES §3.12 for merge conflicts in .po/.pot.
## Description of the implemented changes The changes were: - [ ] Bugfixing - [x] New Feature - [ ] Breaking Change - [ ] Refactoring **Goal:** Add a configurable public join flow (double opt-in, join requests) and admin approval UI, plus configurable SMTP for transactional emails (join confirmation, password reset, etc.) with a test-email action in Global Settings. --- ## What has been changed? ### Public join flow & join requests - **Public join page** (`/join`): Unauthenticated form; admin-configurable fields (member + custom); submit creates a `JoinRequest` in status `pending_confirmation`; confirmation email with link; after link click, status becomes `submitted`. See `docs/onboarding-join-concept.md`. - **JoinRequest resource** (Ash): Status flow, confirmation token (hashed in DB), form data filtered by allowlist; changes for confirm, approve, reject, and join-form field normalization. - **Join confirmation email** (Swoosh): Layout and template; sent on submit; uses `Mv.Mailer` and `mail_from/0`. - **Rate limiting** for join submissions (`MvWeb.JoinRateLimit`). - **Cleanup task** `mix join_requests.cleanup_expired` for expired confirmation tokens. - **Plugs:** `JoinFormEnabled` (only when join form is enabled in settings); `CheckPagePermission` updated for new routes. - **Router:** Public `/join`, confirm route, and (admin) join-request list/show routes. ### Admin: join request approval UI - **Join request list** (LiveView): Filter by status; links to show. - **Join request show:** Display form data; **Approve** and **Reject** actions with optional reason; policies so only users with join-request access can approve/reject. - **Sidebar:** Entry for “Join requests” when permitted. ### SMTP configuration (Global Settings) - **Settings (DB):** New attributes for SMTP (host, port, username, password, TLS/SSL) and sender identity (`smtp_from_name`, `smtp_from_email`). ENV overrides Settings (same pattern as OIDC/Vereinfacht). See `docs/smtp-configuration-concept.md`. - **Mv.Config:** Helpers `smtp_*`, `mail_from_name/0`, `mail_from_email/0`, and `*_env_set?/0`; password from ENV, `SMTP_PASSWORD_FILE`, or Settings (sensitive). - **Mv.Mailer:** Swoosh mailer; `mail_from/0` from ENV or Settings; `send_test_email/1` with classified errors (`:sender_rejected`, `:auth_failed`, `:tls_failed`, etc.); `smtp_config/0` for Settings-only SMTP; TLS options for OTP 27 (e.g. self-signed certs). - **Global Settings UI:** SMTP section with host/port/username/password/TLS/SSL and sender name/email; hint that sender email should match SMTP user; “Test email” form with recipient input and success/error messages; production warning when SMTP is not configured. - **AshAuthentication senders** (password reset, user confirmation): Use `deliver/1` instead of `deliver!/1`; log delivery failures, do not crash caller. - **Migrations:** SMTP columns and `smtp_from_name` / `smtp_from_email` on settings table. ### Other - **Member index:** Filter component and URL param handling (e.g. filter state in URL). - **Email layout:** Shared layout and templates for transactional emails (join confirmation, password reset, user confirmation). - **Docs:** `docs/smtp-configuration-concept.md`, `docs/onboarding-join-concept.md`; updates to `CODE_GUIDELINES.md` (Email §3.11, Gettext merge workflow in §3.12), `docs/feature-roadmap.md`, `docs/page-permission-route-coverage.md`, development log. - **Gettext:** New and updated strings; DE translations for new UI and SMTP messages. - **Config:** `runtime.exs` SMTP and `mail_from` from ENV; `test.exs` mailer adapter; release/docker-entrypoint and Drone adjustments as needed. --- ## Definition of Done ### Code Quality - [x] No new technical depths - [x] Linting passed - [x] Documentation is added where needed (concept docs, CODE_GUIDELINES, inline where useful) ### Accessibility - [x] New elements are properly defined with html-tags - [x] Colour contrast follows WCAG criteria - [ ] Aria labels are added when needed *(review: join form, approval UI, SMTP test section)* - [x] Everything is accessible by keyboard - [ ] Tab-Order is comprehensible *(review: join form and approval modals)* - [ ] All interactive elements have a visible focus *(review: custom buttons/links in new LiveViews)* ### Testing - [x] Tests for new code are written (join requests, join flow, approval, SMTP config, mailer, global settings SMTP section) - [x] All tests pass - [ ] axe-core dev tools show no critical or major issues *(please run on /join and join-request list/show)* --- ## Additional Notes - **Review focus:** Join flow (allowlist, token handling, rate limit), approval policies and who can approve/reject, SMTP precedence (ENV vs Settings) and test-email error handling, and that no secrets (e.g. SMTP password) are exposed in UI or logs. - **Config:** In production, set `MAIL_FROM_EMAIL` (and optionally `MAIL_FROM_NAME`) to match the SMTP user if using ENV; otherwise configure “Sender email (From)” in Global Settings. Sender address must usually match the SMTP account to avoid 553 rejections. - **Gettext:** After merging, run `mix gettext.extract --merge` if new strings were added on main; see CODE_GUIDELINES §3.12 for merge conflicts in `.po`/`.pot`.
simon added 3 commits 2026-03-12 13:55:46 +01:00
feat: add smtp settings
All checks were successful
continuous-integration/drone/push Build is passing
a4f3aa5d6f
Merge remote-tracking branch 'origin/main' into feature/308-web-form
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is failing
4af80a8305
simon added 1 commit 2026-03-12 15:30:28 +01:00
refactor: adress review
All checks were successful
continuous-integration/drone/push Build is passing
942f2afd9e
simon added 1 commit 2026-03-12 15:46:59 +01:00
fix group performance test
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/promote/production Build is passing
a5ce7cb921
simon merged commit d94f9ae42e into main 2026-03-12 15:59:01 +01:00
Sign in to join this conversation.
No description provided.