Files
nf-mail-relay/README.md
T
wmj c0b8981629 Initial commit: HTTP wrapper around the existing falah-ibaas email connector
Gives Supabase Edge Functions (and anything else outside the VPS) a real,
authenticated endpoint onto the VPS's already-working internal Postfix
relay (the same one Ghost uses in production), via the falah-ibaas
EmailConnector that was fully built but never actually deployed.

Deployed live at https://nfmailrelay.falahos.my as a Docker Swarm service
on the existing Traefik network, TLS via Let's Encrypt, shared-secret
bearer auth. Built for Nur Falah's heir notification emails.
2026-08-14 08:00:28 +08:00

67 lines
2.8 KiB
Markdown

# nf-mail-relay
Small HTTP wrapper around the existing `falah-ibaas` email connector
(`/opt/falah-ibaas/connectors/email` on the Falah OS VPS), so services that
can't reach the VPS's internal Postfix relay directly — like a Supabase Edge
Function running on Supabase's cloud — get a real, internet-reachable,
authenticated endpoint that forwards to it.
Built for Nur Falah's heir (warith) notification emails, but generic enough
to reuse for anything else that needs "send an email via the VPS's existing
working mail path" without provisioning a third-party provider.
## Why this exists
The VPS already has a working SMTP relay — Ghost uses it in production
(`mail__options__host=172.17.0.1:25`, no auth, internal Docker bridge only).
There's also a fully-built but never-deployed `EmailConnector` class at
`/opt/falah-ibaas/connectors/email/handler.py` that wraps `smtplib` with
proper error handling. Neither was reachable from outside the VPS. This
relay is the missing piece: a thin, auth-gated HTTP front door onto that
connector.
## Endpoints
- `GET /health` — connector status + send/error metrics
- `POST /send` — send an email
- Header: `X-Relay-Secret: <shared secret>`
- Body: `{ "to": "...", "subject": "...", "body_text": "...", "body_html": "...", "cc": "...", "bcc": "..." }`
## Deploy
```bash
docker build -t nf-mail-relay:latest .
docker service create \
--name nf_mail_relay \
--mount type=bind,source=/opt/falah-ibaas/connectors/email,target=/opt/falah-ibaas/connectors/email,readonly \
--network falah_traefik-net \
--constraint node.role==manager \
--env RELAY_SECRET=<generate with: openssl rand -hex 24> \
--env SMTP_HOST=172.17.0.1 \
--env SMTP_PORT=25 \
--env SMTP_FROM=notifications@falahos.my \
--label traefik.enable=true \
--label 'traefik.http.routers.nfmailrelay.rule=Host(`nfmailrelay.falahos.my`)' \
--label traefik.http.routers.nfmailrelay.entrypoints=websecure \
--label traefik.http.routers.nfmailrelay.tls=true \
--label traefik.http.routers.nfmailrelay.tls.certresolver=letsencrypt \
--label traefik.http.services.nfmailrelay.loadbalancer.server.port=8091 \
nf-mail-relay:latest
```
Currently deployed at `https://nfmailrelay.falahos.my` on the Falah OS VPS
(13.140.161.244), covered by the `*.falahos.my` wildcard DNS — no new DNS
record needed.
## Security notes
- `RELAY_SECRET` is never committed here — it's set as a Docker service
environment variable on deploy. Rotate with `docker service update
--env-add RELAY_SECRET=<new value> nf_mail_relay`.
- The connector directory is bind-mounted **read-only** — this service
cannot modify `falah-ibaas`.
- No auth is used against the Postfix relay itself since it's only bound to
the internal Docker bridge (`172.17.0.1`) — this service is the actual
security boundary between the public internet and that relay.