feat(email): add listmonk-hc second instance for the healthcare HOT stream

Isolated from the trucking listmonk: own DB (listmonk_hc), own uploads volume,
own sliding-window cap. Configured (on dev) with 3 SMTP servers pointing at the
host Postfix hc submission ports 2526/2527/2528 so it round-robins the dedicated
hc IPs .107/.108/.109. Reaches the host MTA via the docker bridge gateway.

Note: the listmonk image needs an explicit one-time '--install --idempotent
--yes' against listmonk_hc (env vars alone do not auto-install this image tag).

Validated on dev: listmonk-hc container (172.19.0.16) -> host :2526 (hcsubmit107)
-> hcout1 (.107) -> real gmail MX; both listmonk instances Up.
This commit is contained in:
justin 2026-06-05 19:18:35 -05:00
parent 70d742df08
commit 08d5132459

View file

@ -306,6 +306,43 @@ services:
- api-postgres
restart: unless-stopped
# Second Listmonk instance for the HEALTHCARE HOT stream (dual-stream email
# design, see docs/healthcare-email-stream-plan.md). Fully isolated from the
# trucking-discipline instance above:
# - its own DB (listmonk_hc) => separate contacts / bounce / complaint state
# - its own sliding-window cap (the healthcare 10k/day ceiling), driven by
# pw-hc-rampcap off /etc/postfix/hc-warmup-start
# - sends ONLY via the host Postfix hc submission ports 2526/2527/2528, which
# egress from the dedicated hc IPs .107/.108/.109 (hcmta01-03). Configure
# these three as Listmonk SMTP servers so it round-robins the hc IPs.
# Reaches the host MTA via the docker bridge gateway 172.18.0.1 (in postfix
# mynetworks 172.16/12). host.docker.internal is mapped for convenience.
listmonk-hc:
image: listmonk/listmonk:latest
ports:
- "9101:9000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- LISTMONK_app__address=0.0.0.0:9000
- LISTMONK_db__host=api-postgres
- LISTMONK_db__port=5432
- LISTMONK_db__user=pw
- LISTMONK_db__password=${DB_PASSWORD:-pw_dev_2026}
- LISTMONK_db__database=listmonk_hc
- LISTMONK_db__ssl_mode=disable
- LISTMONK_db__max_open=25
- LISTMONK_db__max_idle=25
- LISTMONK_db__max_lifetime=300s
- LISTMONK_ADMIN_USER=${LISTMONK_USER:-admin}
- LISTMONK_ADMIN_PASSWORD=${LISTMONK_HC_PASSWORD:-${LISTMONK_PASSWORD}}
- TZ=America/New_York
volumes:
- listmonk-hc-uploads:/listmonk/uploads
depends_on:
- api-postgres
restart: unless-stopped
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
@ -444,6 +481,7 @@ volumes:
erpnext-sites:
erpnext-mariadb-data:
listmonk-uploads:
listmonk-hc-uploads:
umami-pgdata:
prometheus-data:
grafana-data: