feat: add Mailpit SMTP relay and migrate all services

- Add Mailpit service to NET stack with web UI at mailpit.pivoine.art
- Configure Mailpit to relay all emails through IONOS SMTP
- Migrate all 11+ services to use Mailpit instead of direct IONOS SMTP:
  * SEXY: Directus API
  * UTIL: Joplin, Mattermost, Vaultwarden, Tandoor, Linkwarden
  * DEV: Gitea, n8n, Asciinema
  * AI: Open WebUI
  * NET: Netdata (via msmtp)
- Centralize SMTP credentials in mailpit-relay.yaml
- Simplify service configs (no auth/TLS for internal SMTP)
- Enable email monitoring via Mailpit web UI with Basic Auth

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-15 18:34:38 +01:00
parent 5bc790b79b
commit 51267cc674
8 changed files with 90 additions and 58 deletions

View File

@@ -53,14 +53,12 @@ services:
RAG_EMBEDDING_MODEL: ${AI_RAG_EMBEDDING_MODEL:-text-embedding-3-small}
VECTOR_DB: ${AI_VECTOR_DB:-pgvector}
# Email configuration (IONOS SMTP)
SMTP_HOST: ${EMAIL_SMTP_HOST}
SMTP_PORT: ${EMAIL_SMTP_PORT}
SMTP_USER: ${EMAIL_SMTP_USER}
SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD}
# Email configuration (Mailpit SMTP relay)
SMTP_HOST: net_mailpit
SMTP_PORT: 1025
SMTP_FROM_EMAIL: ${EMAIL_FROM}
SMTP_USE_TLS: false
SMTP_USE_SSL: true
SMTP_USE_SSL: false
volumes:
- ai_webui_data:/app/backend/data

View File

@@ -122,6 +122,9 @@ envs:
NET_TRACK_DOCKER_IMAGE: ghcr.io/umami-software/umami:postgresql-latest
NET_TRACK_TRAEFIK_HOST: umami.pivoine.art
NET_TRACK_DB_NAME: umami
# Mailpit SMTP Relay
NET_MAILPIT_IMAGE: axllent/mailpit:latest
NET_MAILPIT_TRAEFIK_HOST: mailpit.pivoine.art
# AI Stack
AI_TRAEFIK_ENABLED: true
AI_COMPOSE_PROJECT_NAME: ai

View File

@@ -32,11 +32,9 @@ services:
GITEA__server__SSH_PORT: 2222
GITEA__server__SSH_LISTEN_PORT: 2222
GITEA__mailer__ENABLED: true
GITEA__mailer__PROTOCOL: smtps
GITEA__mailer__SMTP_ADDR: ${EMAIL_SMTP_HOST}
GITEA__mailer__SMTP_PORT: ${EMAIL_SMTP_PORT}
GITEA__mailer__USER: ${EMAIL_SMTP_USER}
GITEA__mailer__PASSWD: ${EMAIL_SMTP_PASSWORD}
GITEA__mailer__PROTOCOL: smtp
GITEA__mailer__SMTP_ADDR: net_mailpit
GITEA__mailer__SMTP_PORT: 1025
GITEA__mailer__FROM: ${EMAIL_FROM}
GITEA__service__DISABLE_REGISTRATION: false
GITEA__service__REQUIRE_SIGNIN_VIEW: false
@@ -200,12 +198,10 @@ services:
N8N_PROTOCOL: https
WEBHOOK_URL: https://${DEV_N8N_TRAEFIK_HOST}/
N8N_EMAIL_MODE: smtp
N8N_SMTP_HOST: ${EMAIL_SMTP_HOST}
N8N_SMTP_PORT: ${EMAIL_SMTP_PORT}
N8N_SMTP_USER: ${EMAIL_SMTP_USER}
N8N_SMTP_PASS: ${EMAIL_SMTP_PASSWORD}
N8N_SMTP_HOST: net_mailpit
N8N_SMTP_PORT: 1025
N8N_SMTP_SENDER: ${EMAIL_FROM}
N8N_SMTP_SSL: "true"
N8N_SMTP_SSL: "false"
MATTERMOST_WEBHOOK_URL: ${MATTERMOST_WEBHOOK_URL:-}
depends_on:
- postgres
@@ -243,9 +239,8 @@ services:
URL_HOST: ${DEV_ASCIINEMA_TRAEFIK_HOST}
URL_SCHEME: https
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${CORE_DB_HOST}/${DEV_ASCIINEMA_DB_NAME}?pool_size=10
SMTP_HOST: ${EMAIL_SMTP_HOST}
SMTP_USERNAME: ${EMAIL_SMTP_USER}
SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD}
SMTP_HOST: net_mailpit
SMTP_PORT: 1025
SMTP_FROM_ADDRESS: ${EMAIL_FROM}
SIGN_UP_DISABLED: ${DEV_ASCIINEMA_SIGN_UP_DISABLED:-false}
DEFAULT_AVATAR: gravatar

View File

@@ -223,6 +223,43 @@ services:
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.loadbalancer.server.port=3000'
- 'traefik.docker.network=${NETWORK_NAME}'
# Mailpit - SMTP server with web UI
mailpit:
image: ${NET_MAILPIT_IMAGE:-axllent/mailpit:latest}
container_name: ${NET_COMPOSE_PROJECT_NAME}_mailpit
restart: unless-stopped
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
# SMTP relay configuration for IONOS
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
MP_MAX_MESSAGES: 5000
# SMTP relay to IONOS
MP_SMTP_RELAY_CONFIG: /config/relay.yaml
volumes:
- mailpit_data:/data
- ./mailpit-relay.yaml:/config/relay.yaml:ro
networks:
- compose_network
labels:
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
# HTTP to HTTPS redirect
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure.redirectscheme.scheme=https'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.entrypoints=web'
# HTTPS router with auth
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-mailpit-auth.basicauth.users=${AUTH_USERS}'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.tls.certresolver=resolver'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.entrypoints=web-secure'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-mailpit-auth,security-headers@file'
# Service
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.loadbalancer.server.port=8025'
- 'traefik.docker.network=${NETWORK_NAME}'
# Watchtower
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
volumes:
letsencrypt_data:
name: ${NET_COMPOSE_PROJECT_NAME}_letsencrypt_data
@@ -232,6 +269,8 @@ volumes:
name: ${NET_COMPOSE_PROJECT_NAME}_netdata_lib
netdata_cache:
name: ${NET_COMPOSE_PROJECT_NAME}_netdata_cache
mailpit_data:
name: ${NET_COMPOSE_PROJECT_NAME}_mailpit_data
networks:
compose_network:

11
net/mailpit-relay.yaml Normal file
View File

@@ -0,0 +1,11 @@
# Mailpit SMTP Relay Configuration
# Relays all outbound emails through IONOS SMTP
# Default relay for all emails
relay:
host: ${EMAIL_SMTP_HOST}
port: ${EMAIL_SMTP_PORT}
username: ${EMAIL_SMTP_USER}
password: ${EMAIL_SMTP_PASSWORD}
starttls: true
auth: plain

View File

@@ -2,19 +2,15 @@
# Set default values for all accounts
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
auth off
tls off
logfile /var/log/msmtp.log
# IONOS SMTP account
account ionos
host smtp.ionos.de
port 465
tls_starttls off
# Mailpit SMTP relay account
account mailpit
host net_mailpit
port 1025
from hi@pivoine.art
user hi@pivoine.art
password jaquoment
# Set default account
account default : ionos
account default : mailpit

View File

@@ -33,12 +33,10 @@ services:
EXTENSIONS_PATH: ${SEXY_EXTENSIONS_PATH:-./extensions}
EXTENSIONS_AUTO_RELOAD: ${SEXY_EXTENSIONS_AUTO_RELOAD:-false}
CONTENT_SECURITY_POLICY_DIRECTIVES__FRAME_SRC: ${SEXY_CONTENT_SECURITY_POLICY_DIRECTIVES__FRAME_SRC}
EMAIL_TRANSPORT: ${EMAIL_TRANSPORT}
EMAIL_TRANSPORT: smtp
EMAIL_FROM: ${EMAIL_FROM}
EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST}
EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT}
EMAIL_SMTP_USER: ${EMAIL_SMTP_USER}
EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD}
EMAIL_SMTP_HOST: net_mailpit
EMAIL_SMTP_PORT: 1025
USER_REGISTER_URL_ALLOW_LIST: ${SEXY_USER_REGISTER_URL_ALLOW_LIST}
PASSWORD_RESET_URL_ALLOW_LIST: ${SEXY_PASSWORD_RESET_URL_ALLOW_LIST}
labels:

View File

@@ -54,11 +54,9 @@ services:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
MAILER_ENABLED: 1
MAILER_HOST: ${EMAIL_SMTP_HOST}
MAILER_PORT: ${EMAIL_SMTP_PORT}
MAILER_SECURE: 1
MAILER_AUTH_USER: ${EMAIL_SMTP_USER}
MAILER_AUTH_PASSWORD: ${EMAIL_SMTP_PASSWORD}
MAILER_HOST: net_mailpit
MAILER_PORT: 1025
MAILER_SECURE: 0
MAILER_NOREPLY_NAME: Joplin Server
MAILER_NOREPLY_EMAIL: ${EMAIL_FROM}
networks:
@@ -97,7 +95,7 @@ services:
BASE_URL: https://${UTIL_LINKS_TRAEFIK_HOST}
NEXT_PUBLIC_EMAIL_PROVIDER: true
EMAIL_FROM: ${EMAIL_FROM}
EMAIL_SERVER: ${LINKS_EMAIL_SERVER}
EMAIL_SERVER: smtp://net_mailpit:1025
volumes:
- linkwarden_data:/data/data
depends_on:
@@ -156,12 +154,10 @@ services:
MM_SERVICESETTINGS_SITEURL: https://${UTIL_MATTERMOST_TRAEFIK_HOST}
MM_SERVICESETTINGS_ENABLELOCALMODE: "true"
# Email settings
MM_EMAILSETTINGS_ENABLESMTPAUTH: "true"
MM_EMAILSETTINGS_SMTPUSERNAME: ${EMAIL_SMTP_USER}
MM_EMAILSETTINGS_SMTPPASSWORD: ${EMAIL_SMTP_PASSWORD}
MM_EMAILSETTINGS_SMTPSERVER: ${EMAIL_SMTP_HOST}
MM_EMAILSETTINGS_SMTPPORT: ${EMAIL_SMTP_PORT}
MM_EMAILSETTINGS_CONNECTIONSECURITY: TLS
MM_EMAILSETTINGS_ENABLESMTPAUTH: "false"
MM_EMAILSETTINGS_SMTPSERVER: net_mailpit
MM_EMAILSETTINGS_SMTPPORT: 1025
MM_EMAILSETTINGS_CONNECTIONSECURITY: ""
MM_EMAILSETTINGS_FEEDBACKNAME: Mattermost
MM_EMAILSETTINGS_FEEDBACKEMAIL: ${EMAIL_FROM}
MM_EMAILSETTINGS_REPLYTOADDRESS: ${EMAIL_FROM}
@@ -200,13 +196,11 @@ services:
SIGNUPS_ALLOWED: ${UTIL_VAULT_SIGNUPS_ALLOWED:-false}
INVITATIONS_ALLOWED: ${UTIL_VAULT_INVITATIONS_ALLOWED:-true}
SHOW_PASSWORD_HINT: ${UTIL_VAULT_SHOW_PASSWORD_HINT:-false}
SMTP_HOST: ${EMAIL_SMTP_HOST}
SMTP_HOST: net_mailpit
SMTP_FROM: ${EMAIL_FROM}
SMTP_FROM_NAME: Vaultwarden
SMTP_SECURITY: force_tls
SMTP_PORT: ${EMAIL_SMTP_PORT}
SMTP_USERNAME: ${EMAIL_SMTP_USER}
SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD}
SMTP_SECURITY: off
SMTP_PORT: 1025
networks:
- compose_network
labels:
@@ -248,12 +242,10 @@ services:
REVERSE_PROXY_AUTH: ${UTIL_TANDOOR_REVERSE_PROXY_AUTH:-0}
# Email configuration (IONOS SMTP)
EMAIL_HOST: ${EMAIL_SMTP_HOST}
EMAIL_PORT: ${EMAIL_SMTP_PORT}
EMAIL_HOST_USER: ${EMAIL_SMTP_USER}
EMAIL_HOST_PASSWORD: ${EMAIL_SMTP_PASSWORD}
EMAIL_USE_TLS: ${UTIL_TANDOOR_EMAIL_USE_TLS:-0}
EMAIL_USE_SSL: ${UTIL_TANDOOR_EMAIL_USE_SSL:-1}
EMAIL_HOST: net_mailpit
EMAIL_PORT: 1025
EMAIL_USE_TLS: 0
EMAIL_USE_SSL: 0
DEFAULT_FROM_EMAIL: ${EMAIL_FROM}
# Gunicorn settings