From 24270af2f0f6c77bde956fffd0866b08cbdb7d40 Mon Sep 17 00:00:00 2001 From: Eduardo David Paredes Vara Date: Fri, 20 Mar 2026 22:35:42 +0000 Subject: [PATCH] Mail --- mail-relay/README.md | 137 ++++++++++++++++++++++++++++++++++ mail-relay/docker-compose.yml | 52 +++++++++++++ mail-relay/stack.env | 29 +++++++ 3 files changed, 218 insertions(+) create mode 100644 mail-relay/README.md create mode 100644 mail-relay/docker-compose.yml create mode 100644 mail-relay/stack.env diff --git a/mail-relay/README.md b/mail-relay/README.md new file mode 100644 index 0000000..a9d0726 --- /dev/null +++ b/mail-relay/README.md @@ -0,0 +1,137 @@ +# Mail Relay - SMTP de salida para stacks + +Stack de relay SMTP interno para centralizar el envio de correos de tus apps sin montar un servidor de correo completo. + +## πŸ“‹ Descripcion + +Este stack despliega un relay SMTP con Postfix usando `boky/postfix` para: +- Recibir correo SMTP desde contenedores internos +- Reenviar todo a un proveedor SMTP externo (smarthost) +- Firmar con DKIM (autogenerado) +- Unificar configuracion de correo para todos los stacks + +No incluye recepcion de correo (MX, IMAP, POP3, webmail). + +## πŸš€ Despliegue + +### 1. Preparar rutas y secreto en el host + +```bash +sudo mkdir -p /opt/mail-relay/{queue,opendkim,secrets} +sudo chmod 700 /opt/mail-relay/secrets +printf '%s' 'CAMBIA_ESTA_PASSWORD_SMTP' | sudo tee /opt/mail-relay/secrets/relayhost_password > /dev/null +sudo chmod 600 /opt/mail-relay/secrets/relayhost_password +``` + +### 2. Desplegar desde Portainer + +1. Ve a **Stacks** -> **Add stack** +2. Nombre: `mail-relay` +3. Configura el repositorio Git +4. Compose path: `mail-relay/docker-compose.yml` +5. Carga variables desde `mail-relay/stack.env` +6. Ajusta al menos: + - `MAIL_RELAY_HOSTNAME` + - `MAIL_RELAY_ALLOWED_SENDER_DOMAINS` + - `MAIL_RELAY_MASQUERADED_DOMAINS` + - `MAIL_RELAY_SMARTHOST` + - `MAIL_RELAY_SMARTHOST_USERNAME` +7. Deploy del stack + +## βš™οΈ Variables importantes + +```env +MAIL_RELAY_SMARTHOST=[smtp.proveedor.tld]:587 +MAIL_RELAY_SMARTHOST_USERNAME=usuario-smtp +MAIL_RELAY_SMTP_TLS_SECURITY_LEVEL=encrypt +MAIL_RELAY_ALLOWED_SENDER_DOMAINS=tudominio.com +MAIL_RELAY_MASQUERADED_DOMAINS=tudominio.com +``` + +La password SMTP no se pone en `stack.env`; se lee desde el archivo host: + +```text +/opt/mail-relay/secrets/relayhost_password +``` + +## πŸ”Œ Conectar otras apps + +En cada stack que deba enviar correo, aΓ±ade la red externa: + +```yaml +networks: + mail_internal: + external: true +``` + +Y en el servicio de la app: + +```yaml +services: + tu-app: + networks: + - default + - mail_internal +``` + +Config SMTP en la app: + +```env +SMTP_HOST=mail-relay +SMTP_PORT=587 +SMTP_FROM=noreply@tudominio.com +``` + +## βœ… DNS minimo recomendado + +Para buena entregabilidad en Gmail/Outlook: +- SPF +- DKIM +- DMARC + +### SPF (ejemplo) + +```text +v=spf1 include:spf.tu-proveedor.tld ~all +``` + +### DKIM + +Tras el primer arranque, extrae el TXT generado: + +```bash +find /opt/mail-relay/opendkim -type f -name '*.txt' -exec echo '### {}' \; -exec cat {} \; +``` + +Copia esos valores a tu DNS. + +### DMARC (inicio en monitorizacion) + +```text +v=DMARC1; p=none; adkim=s; aspf=s +``` + +## πŸ§ͺ Prueba rapida + +```bash +docker exec -i mail-relay sendmail -t <<'EOF' +From: noreply@tudominio.com +To: destino@example.com +Subject: prueba mail relay + +Correo de prueba del stack mail-relay. +EOF +``` + +## πŸ› οΈ Troubleshooting + +Ver logs: + +```bash +docker logs -f mail-relay +``` + +Errores tipicos: +- `Relay access denied`: revisa `MAIL_RELAY_ALLOWED_SENDER_DOMAINS` +- Auth fallida con proveedor: revisa usuario/password SMTP +- Rechazo por DNS: valida SPF/DKIM/DMARC \ No newline at end of file diff --git a/mail-relay/docker-compose.yml b/mail-relay/docker-compose.yml new file mode 100644 index 0000000..8f078b9 --- /dev/null +++ b/mail-relay/docker-compose.yml @@ -0,0 +1,52 @@ +services: + mail-relay: + image: ${MAIL_RELAY_IMAGE} + container_name: mail-relay + restart: unless-stopped + environment: + TZ: ${TZ} + LOG_FORMAT: ${MAIL_RELAY_LOG_FORMAT} + + # Hostname del relay + POSTFIX_myhostname: ${MAIL_RELAY_HOSTNAME} + + # Solo clientes internos del stack de correo + POSTFIX_mynetworks: ${MAIL_RELAY_MYNETWORKS} + + # Dominios permitidos para el sender + ALLOWED_SENDER_DOMAINS: ${MAIL_RELAY_ALLOWED_SENDER_DOMAINS} + + # Reescritura de dominio para hosts internos + MASQUERADED_DOMAINS: ${MAIL_RELAY_MASQUERADED_DOMAINS} + + # Relay SMTP externo + RELAYHOST: ${MAIL_RELAY_SMARTHOST} + RELAYHOST_USERNAME: ${MAIL_RELAY_SMARTHOST_USERNAME} + RELAYHOST_PASSWORD_FILE: /run/secrets/relayhost_password + POSTFIX_smtp_tls_security_level: ${MAIL_RELAY_SMTP_TLS_SECURITY_LEVEL} + + # DKIM + DKIM_AUTOGENERATE: ${MAIL_RELAY_DKIM_AUTOGENERATE} + DKIM_SELECTOR: ${MAIL_RELAY_DKIM_SELECTOR} + + volumes: + - ${MAIL_RELAY_QUEUE_PATH}:/var/spool/postfix:Z + - ${MAIL_RELAY_DKIM_KEYS_PATH}:/etc/opendkim/keys:Z + - ${MAIL_RELAY_PASSWORD_FILE_PATH}:/run/secrets/relayhost_password:ro,Z + + networks: + mail_internal: + ipv4_address: ${MAIL_RELAY_IPV4} + + # No publicar puertos al exterior para uso interno entre contenedores. + # Descomenta para pruebas desde el host: + # ports: + # - "127.0.0.1:1587:587" + +networks: + mail_internal: + name: ${MAIL_RELAY_NETWORK_NAME} + driver: bridge + ipam: + config: + - subnet: ${MAIL_RELAY_SUBNET} \ No newline at end of file diff --git a/mail-relay/stack.env b/mail-relay/stack.env new file mode 100644 index 0000000..6244b5c --- /dev/null +++ b/mail-relay/stack.env @@ -0,0 +1,29 @@ +##### General ##### +MAIL_RELAY_IMAGE=boky/postfix:v5.1.0 +TZ=Europe/Madrid +MAIL_RELAY_LOG_FORMAT=plain + +##### Network ##### +MAIL_RELAY_NETWORK_NAME=mail_internal +MAIL_RELAY_SUBNET=10.77.0.0/24 +MAIL_RELAY_IPV4=10.77.0.10 +MAIL_RELAY_MYNETWORKS=127.0.0.0/8,10.77.0.0/24 + +##### Relay identity ##### +MAIL_RELAY_HOSTNAME=mail.example.com +MAIL_RELAY_ALLOWED_SENDER_DOMAINS=example.com +MAIL_RELAY_MASQUERADED_DOMAINS=example.com + +##### Upstream SMTP (smarthost) ##### +MAIL_RELAY_SMARTHOST=[in-v3.mailjet.com]:587 +MAIL_RELAY_SMARTHOST_USERNAME=tu-api-key-mailjet +MAIL_RELAY_SMTP_TLS_SECURITY_LEVEL=encrypt + +##### DKIM ##### +MAIL_RELAY_DKIM_AUTOGENERATE=true +MAIL_RELAY_DKIM_SELECTOR=mail + +##### Host paths ##### +MAIL_RELAY_QUEUE_PATH=/opt/mail-relay/queue +MAIL_RELAY_DKIM_KEYS_PATH=/opt/mail-relay/opendkim +MAIL_RELAY_PASSWORD_FILE_PATH=/opt/mail-relay/secrets/relayhost_password \ No newline at end of file