+++ title = "Configurar correo saliente para recuperación de contraseña en Zammad y Grafana" description = "Zammad tenía la credencial SMTP de salida desincronizada del buzón real (los resets de contraseña fallaban silenciosamente); Grafana no tenía SMTP configurado en absoluto. Se creó una cuenta dedicada de solo-salida y se configuró en ambos servicios, sin tocar el buzón soporte@ que Zammad usa para recibir tickets." date = 2026-08-24T20:49:04Z authors = ["gen"] slug = "mem-20260824-254312-configurar-correo-saliente-para-recuperacion-de-contrasena-en-zammad-y-grafana" template = "memory.html" [taxonomies] categories = ["memorias"] tags = ["correo", "docker-mailserver", "grafana", "smtp", "zammad"] systems = ["grafana", "mail-server", "mcps-hpc-01", "mcps-vpn-server", "zammad"] [extra] id = "MEM-20260824-254312" kind = "memory" author_id = "gen" author_fingerprint = "SHA256:JhN1Tt4jYqWoJIznDJ6QkMAiOR6HFHr3xLz9aBJqmPg" risk = "medium" ticket = "" review_required = true review_policy = "all-active" reviewer_snapshot = true reviewers = ["gen"] started_at = "" finished_at = "" duration_minutes = 0 agent = "claude-code" +++ ## Contexto El usuario pidió configurar correo saliente en mail.mcps-epcm.org (10.8.0.1, mcps-vpn-server) para que soporte.mcps-epcm.org (Zammad) y grafana.mcps-epcm.org (Grafana, ambos en mcps-hpc-01) puedan mandar el correo de 'olvidé mi contraseña'. Diagnóstico: el contenedor zammad-railsserver tenía SMTP_USER_NAME=soporte@mcps-epcm.org y un SMTP_PASSWORD que ya NO coincidía con la contraseña real del buzón (confirmado con un intento swaks que produjo 'Password mismatch' / 'SASL LOGIN authentication failed' en el log de postfix). Ese mismo buzón soporte@ es el canal de ENTRADA real de Zammad (Channel id=1, área Email::Notification para el saliente; hay además un Channel id=5 de tipo IMAP que zammad-fetch-mail.timer sondea cada 60s para crear tickets desde correos entrantes — ese canal sí tiene la contraseña correcta, guardada en la base de datos de Zammad, no accesible desde fuera). Rotar la contraseña de soporte@ habría arreglado el saliente pero roto el sondeo IMAP de entrada (Channel 5), que sigue funcionando con normalidad. Por eso se optó por crear una cuenta nueva dedicada solo a notificaciones automáticas salientes (notificaciones@mcps-epcm.org), dejando soporte@ intacto. Grafana no tenía ninguna sección [smtp] activa (todo comentado/default) ni SSO configurado (auth local activa por default), así que hoy era literalmente imposible que mandara cualquier correo. Se creó la cuenta en docker-mailserver, se verificó por SMTP con swaks (auth+entrega limpia confirmada en el log de postfix/amavis). Se actualizó el Channel id=1 de Zammad (área Email::Notification) por rails runner dentro del contenedor zammad-railsserver, apuntando host/user/password/domain a la cuenta nueva, dejando notification_sender ('Soporte MCPS ') sin cambios para que el remitente visible siga siendo reconocible aunque la autenticación SMTP real sea con notificaciones@. Se probó un envío real de extremo a extremo replicando el pipeline de entrega de Zammad (Mail.new + delivery_method :smtp con las mismas opciones ya guardadas en el Channel) y llegó limpio. Para Grafana, no había compose file ni bind-mount de config: el contenedor se recrea vía un unit de systemd propio (/etc/systemd/system/container-grafana.service, patrón 'podman run' directo, igual que el de Caddy documentado en el manual RUN-20260819-A3B63B). Se agregó GF_SMTP_* al ExecStart, con GF_SMTP_PASSWORD inyectado en forma 'bare' desde un EnvironmentFile dedicado (/etc/grafana-smtp.env, 600 root:root) — mismo patrón de manejo de secretos que ya usa Caddy con las credenciales de Route53. Se respaldó la unit original antes de editar (container-grafana.service.bak-2026-08-24). Tras systemctl daemon-reload + restart, el contenedor recreado ya expone las variables GF_SMTP_* correctas. No se pudo verificar el flujo completo de 'olvidé mi contraseña' de Grafana desde este entorno (no hay acceso a navegador ni sesión admin de Grafana para disparar su endpoint de test email) — queda pendiente un clic de prueba real por parte de un administrador. ## Cambios realizados - Creada la cuenta notificaciones@mcps-epcm.org en docker-mailserver (mcps-vpn-server), verificada por SMTP con swaks - Actualizado Channel id=1 (Email::Notification, saliente) de Zammad para autenticar con notificaciones@mcps-epcm.org en vez de la contraseña vieja de soporte@; notification_sender se dejó igual - Probado un envío real desde Zammad usando el canal actualizado, confirmado entregado limpio en el log de postfix/amavis - Agregada configuración SMTP a Grafana: nuevo /etc/grafana-smtp.env (600, root:root) con la contraseña, y variables GF_SMTP_ENABLED/HOST/USER/PASSWORD/FROM_ADDRESS/FROM_NAME/STARTTLS_POLICY agregadas al ExecStart de /etc/systemd/system/container-grafana.service (unit original respaldada como .bak-2026-08-24) - systemctl daemon-reload + restart de container-grafana.service; confirmado que el contenedor recreado expone las variables GF_SMTP_* nuevas ## Comandos relevantes (secretos redactados) ```console podman exec mailserver setup email list podman exec mailserver setup email add notificaciones@mcps-epcm.org swaks --to prueba@mcps-epcm.org --from notificaciones@mcps-epcm.org --server mail.mcps-epcm.org:587 --auth LOGIN --auth-user notificaciones@mcps-epcm.org --auth-password --tls --hide-all podman exec zammad-railsserver bash -lc "rails r 'Channel.where(area: %q(Email::Notification))...'" podman exec zammad-railsserver bash -lc "rails r 'c = Channel.find(1); ... c.options[:outbound][:options][:password] = ; c.save!'" podman exec zammad-railsserver bash -lc "rails r 'Mail.new(...).delivery_method(:smtp, ...).deliver'" # prueba end-to-end systemctl cat container-grafana.service cp /etc/systemd/system/container-grafana.service /etc/systemd/system/container-grafana.service.bak-2026-08-24 tee /etc/grafana-smtp.env # GF_SMTP_PASSWORD=, chmod 600 systemctl daemon-reload && systemctl restart container-grafana.service podman inspect grafana --format '{{range .Config.Env}}{{println .}}{{end}}' ``` ## Validación - swaks contra la cuenta notificaciones@ terminó con exit 0 y el log de postfix mostró sasl_username=notificaciones@mcps-epcm.org + amavis 'Passed CLEAN' - Tras actualizar el Channel de Zammad, un envío real replicando su pipeline de entrega (Mail + delivery_method :smtp con las opciones guardadas) terminó en 'OK' y el log de postfix/amavis confirmó entrega limpia desde notificaciones@ hacia prueba@ - podman inspect grafana tras el restart mostró las 7 variables GF_SMTP_* con los valores esperados (incluida la contraseña resuelta desde el EnvironmentFile) - systemctl is-active container-grafana.service devolvió 'active' tras el restart, sin reinicios en bucle ## Riesgo y reversión Restaurar /etc/systemd/system/container-grafana.service.bak-2026-08-24 sobre container-grafana.service, borrar /etc/grafana-smtp.env, systemctl daemon-reload && systemctl restart container-grafana.service para volver Grafana a su estado sin SMTP. En Zammad, el Channel id=1 puede revertirse manualmente (rails runner) a host/user/password de soporte@ si se decide no usar la cuenta dedicada — no hay comando de un solo paso, hay que reconstruir el hash de options a mano. La cuenta notificaciones@mcps-epcm.org puede borrarse con 'setup email del' si se abandona este enfoque; no tiene aliases ni depende de nada más.