feat(dev-deploy): relay Mailpit to Gmail (Stage 3)

Keep Mailpit as the backend's SMTP submission point and turn on its
relay so OTP/notification mail addressed to the owner reaches a real
Gmail inbox, while everything else stays captured-only.

- mailpit gains --smtp-relay-config + --smtp-relay-matching (default
  non-routable, so an unconfigured stack only captures); relay.conf is
  mounted from a new galaxy-dev-mailpit-config volume
- tools/dev-deploy/mailpit/relay.conf.tmpl + a dev-deploy.yaml step that
  renders it from Gitea secrets (Gmail App Password, never committed)
  and seeds the volume; the GALAXY_DEV_MAIL_RELAY_MATCH var drives the
  relay-matching recipient
- backend SMTP config unchanged (still -> galaxy-mailpit:1025)
- dev-deploy README documents the relay + required secrets/vars

Verified locally: compose config valid; the rendered relay.conf is
accepted by mailpit v1.21.8 (relay + recipient-matching enabled).
Real Gmail delivery is verified at the dev-deploy preview once the
owner sets the secrets.
This commit is contained in:
Ilia Denisov
2026-05-31 22:44:32 +02:00
parent 225f89fad6
commit 7fb6a63c2b
4 changed files with 87 additions and 3 deletions
+27 -3
View File
@@ -117,13 +117,37 @@ and the dev-deploy compose ships with it enabled by default:
1. Enter your email address in the login form.
2. Submit `123456` as the code — the docker-compose default for
`BACKEND_AUTH_DEV_FIXED_CODE` is `123456`, so the bcrypt-hashed
email code stays a fallback. To force real Mailpit codes (e.g. for
mail-flow QA), set `BACKEND_AUTH_DEV_FIXED_CODE=` (empty) in a
local `.env` and `make rebuild`.
email code stays a fallback. To force the real email code (which
Mailpit then relays to your Gmail — see **Mail** below), set
`BACKEND_AUTH_DEV_FIXED_CODE=` (empty) and redeploy.
The fixed-code override is rejected by production env loaders, so it
cannot leak into the prod environment.
## Mail
The backend always submits mail to **Mailpit** (`galaxy-mailpit:1025`),
exactly as it would to a production SMTP server. Mailpit captures every
message in its UI (internal `:8025`) and, when configured, **relays**
the ones whose recipient matches `GALAXY_DEV_MAIL_RELAY_MATCH` up to a
real Gmail account — so an OTP addressed to you lands in your real inbox
while everything else stays captured-only.
Configure the relay through Gitea Actions secrets/vars (never
committed); the `dev-deploy.yaml` workflow renders Mailpit's
`relay.conf` (from `tools/dev-deploy/mailpit/relay.conf.tmpl`) and seeds
it into the `galaxy-dev-mailpit-config` volume:
| Name | Kind | Purpose |
| --- | --- | --- |
| `GALAXY_DEV_MAIL_RELAY_USERNAME` | secret | Gmail address used as the relay login + From. |
| `GALAXY_DEV_MAIL_RELAY_PASSWORD` | secret | Gmail **App Password** (requires 2FA; not the account password). |
| `GALAXY_DEV_MAIL_RELAY_MATCH` | var | Recipient regex to auto-relay (e.g. your Gmail address). Unset → capture-only. |
With none set the stack only captures mail (the compose relay-match
defaults to a non-routable address), so it can never email third
parties.
## Networking
```