mailx es un cliente de correo de línea de comandos que permite a scripts, tareas cron y unidades de systemd enviar mensajes sin intervención humana. Por sí solo no entrega nada: necesita un agente de transporte (MTA) que lleve el correo hasta el destinatario. En este tutorial configurarás Postfix en Ubuntu 24.04 como relay que envía todo a través de un proveedor SMTP autenticado, instalarás mailx y crearás dos alertas reales: una cuando un disco supera un umbral de uso y otra cuando falla un servicio de systemd.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Una cuenta en un proveedor SMTP con credenciales para enviar correo por el puerto 587 (tu propio servidor de correo, Brevo, Amazon SES, SendGrid, Mailgun o Gmail con contraseña de aplicación).
  • Una dirección de remitente que tu proveedor permita usar, por ejemplo alertas@your_domain.
  • Una dirección donde quieras recibir las alertas.

Paso 1: Instalar Postfix, mailx y el soporte SASL

Instala los tres paquetes necesarios: postfix (el MTA), bsd-mailx (el comando mail/mailx) y libsasl2-modules, que Postfix necesita para autenticarse contra el servidor SMTP:

sudo apt update
sudo apt install postfix bsd-mailx libsasl2-modules

Durante la instalación aparece el asistente de Postfix:

  • General mail configuration type: elige Satellite system.
  • System mail name: el nombre completo del servidor, por ejemplo server01.your_domain.
  • SMTP relay host: el servidor de tu proveedor con corchetes y puerto, por ejemplo [smtp.your_provider.com]:587.
  • Root and postmaster mail recipient: puedes dejarlo vacío.

Comprueba que mail apunta a bsd-mailx:

readlink -f "$(command -v mail)"
/usr/bin/bsd-mailx

Paso 2: Configurar Postfix como relay autenticado

Postfix necesita las credenciales del proveedor en un mapa aparte. Crea el archivo:

sudo nano /etc/postfix/sasl_passwd

Añade una línea con el mismo host y puerto que usaste como relay, seguido de usuario y contraseña. Sustituye los valores de ejemplo por los tuyos:

[smtp.your_provider.com]:587 your_smtp_user:your_smtp_password

Protege el archivo, ya que contiene una contraseña en claro, y genera la base de datos que Postfix lee:

sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd

Esto crea /etc/postfix/sasl_passwd.db. Ahora aplica la configuración con postconf -e, que edita /etc/postfix/main.cf de forma segura:

sudo postconf -e 'relayhost = [smtp.your_provider.com]:587'
sudo postconf -e 'smtp_sasl_auth_enable = yes'
sudo postconf -e 'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd'
sudo postconf -e 'smtp_sasl_security_options = noanonymous'
sudo postconf -e 'smtp_tls_security_level = encrypt'
sudo postconf -e 'inet_interfaces = loopback-only'

Qué hace cada ajuste:

  • smtp_tls_security_level = encrypt obliga a usar STARTTLS, de modo que la contraseña nunca viaja sin cifrar.
  • inet_interfaces = loopback-only hace que Postfix solo acepte correo desde el propio servidor. No necesitas exponer el puerto 25 a Internet.

Reescribir el remitente

Por defecto los mensajes salen como [email protected]_domain, una dirección que tu proveedor rechazará o marcará como spam. Con un mapa genérico, Postfix reescribe cualquier remitente local por tu dirección verificada al enviarlo hacia fuera:

sudo nano /etc/postfix/generic
@server01.your_domain    alertas@your_domain

Usa el mismo nombre que pusiste en System mail name. Genera el mapa, actívalo y recarga Postfix:

sudo postmap /etc/postfix/generic
sudo postconf -e 'smtp_generic_maps = hash:/etc/postfix/generic'
sudo systemctl reload postfix

Revisa que no haya errores de configuración:

sudo postfix check && postconf relayhost smtp_generic_maps
relayhost = [smtp.your_provider.com]:587
smtp_generic_maps = hash:/etc/postfix/generic

Paso 3: Enviar un correo de prueba

Envía un mensaje sencillo. El cuerpo se lee de la entrada estándar y el asunto va en -s:

echo "Correo de prueba enviado desde $(hostname -f)" | mail -s "Prueba de mailx" [email protected]

Mira el registro de Postfix para confirmar la entrega:

sudo tail -n 20 /var/log/mail.log

Una entrega correcta contiene status=sent y la respuesta 250 del servidor remoto:

2026-09-25T10:12:04.381220+00:00 server01 postfix/smtp[4312]: 9C1E2A0431: to=<[email protected]>, relay=smtp.your_provider.com[192.0.2.25]:587, delay=1.4, delays=0.02/0.01/0.62/0.75, dsn=2.0.0, status=sent (250 2.0.0 OK)

Algunas opciones de bsd-mailx que usarás en los scripts:

# Varios destinatarios y copia
mail -s "Asunto" -c equipo@your_domain uno@your_domain dos@your_domain < informe.txt

# Añadir una cabecera, por ejemplo Reply-To
echo "Cuerpo" | mail -s "Asunto" -a "Reply-To: soporte@your_domain" [email protected]

Paso 4: Crear una alerta de espacio en disco

Esta alerta revisa todos los sistemas de archivos reales y envía un correo si alguno supera el umbral. Crea el script:

sudo nano /usr/local/bin/check-disk-alert
#!/usr/bin/env bash
set -euo pipefail

THRESHOLD="${THRESHOLD:-85}"
RECIPIENT="${RECIPIENT:[email protected]}"
HOST="$(hostname -f)"

full="$(df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs -x overlay \
  | awk -v t="$THRESHOLD" 'NR > 1 { p = $1; sub(/%/, "", p); if (p + 0 >= t) print $2 " al " p "%" }')"

if [[ -n "$full" ]]; then
  {
    printf 'Sistemas de archivos por encima del %s%% en %s:\n\n%s\n\n' "$THRESHOLD" "$HOST" "$full"
    df -h -x tmpfs -x devtmpfs -x squashfs -x overlay
  } | mail -s "[ALERTA] Disco casi lleno en $HOST" "$RECIPIENT"
fi

Cambia [email protected] por tu dirección. Haz el script ejecutable y pruébalo forzando un umbral del 1 % para que salte seguro:

sudo chmod 755 /usr/local/bin/check-disk-alert
sudo THRESHOLD=1 /usr/local/bin/check-disk-alert

Deberías recibir un correo con un cuerpo parecido a este:

Sistemas de archivos por encima del 1% en server01.your_domain:

/ al 23%
/boot al 12%

Prográmalo con cron para que se ejecute cada 30 minutos:

sudo nano /etc/cron.d/check-disk-alert
[email protected]
*/30 * * * * root /usr/local/bin/check-disk-alert

La variable MAILTO hace que cron te envíe también cualquier salida o error del script, así sabrás si deja de funcionar. Mientras el disco siga por encima del umbral recibirás un aviso cada 30 minutos; si te resulta excesivo, cambia la frecuencia a 0 * * * * (cada hora).

Paso 5: Recibir un correo cuando falla un servicio

systemd permite lanzar una unidad cuando otra falla mediante la directiva OnFailure=. Crearás una unidad plantilla que envía el estado del servicio que ha fallado.

Primero, el script que compone el mensaje:

sudo nano /usr/local/bin/systemd-failure-mail
#!/usr/bin/env bash
set -euo pipefail

UNIT="$1"
RECIPIENT="[email protected]"
HOST="$(hostname -f)"

{
  systemctl status --full --no-pager --lines=30 "$UNIT" || true
} | mail -s "[ALERTA] $UNIT ha fallado en $HOST" "$RECIPIENT"

systemctl status devuelve un código distinto de cero para una unidad fallida; el || true evita que eso haga fallar el script. Hazlo ejecutable:

sudo chmod 755 /usr/local/bin/systemd-failure-mail

Ahora la unidad plantilla. La @ del nombre indica que recibe un parámetro (%i), que será el nombre del servicio que falló:

sudo nano /etc/systemd/system/[email protected]
[Unit]
Description=Aviso por correo del fallo de %i

[Service]
Type=oneshot
ExecStart=/usr/local/bin/systemd-failure-mail %i

Probar con un servicio que falla

Crea un servicio de prueba que siempre falla y que usa la plantilla:

sudo nano /etc/systemd/system/test-fallo.service
[Unit]
Description=Servicio de prueba que falla
OnFailure=failure-mail@%n.service

[Service]
Type=oneshot
ExecStart=/bin/false

%n se sustituye por el nombre completo de la unidad (test-fallo.service). Recarga systemd y arráncalo:

sudo systemctl daemon-reload
sudo systemctl start test-fallo.service

El comando termina con un error, que es lo esperado. Comprueba que la plantilla se ha ejecutado:

journalctl -u 'failure-mail@*' -n 5 --no-pager
Sep 25 10:31:07 server01 systemd[1]: Starting [email protected] - Aviso por correo del fallo de test-fallo.service...
Sep 25 10:31:07 server01 systemd[1]: [email protected]: Deactivated successfully.
Sep 25 10:31:07 server01 systemd[1]: Finished [email protected] - Aviso por correo del fallo de test-fallo.service.

Recibirás un correo con la salida de systemctl status test-fallo.service. Elimina el servicio de prueba:

sudo rm /etc/systemd/system/test-fallo.service
sudo systemctl daemon-reload
sudo systemctl reset-failed

Aplicarlo a un servicio real

Para vigilar un servicio existente, como nginx, añade la directiva con un archivo drop-in en lugar de editar la unidad del paquete:

sudo systemctl edit nginx.service

En el editor, escribe entre los comentarios indicados:

[Unit]
OnFailure=failure-mail@%n.service

Guarda y comprueba que se ha aplicado:

systemctl show nginx.service -p OnFailure

Si el servicio tiene Restart=on-failure, systemd solo lo considera fallido cuando agota los reintentos, así que no recibirás un correo por cada reinicio automático.

Solución de problemas

SASL authentication failed en /var/log/mail.log. Usuario o contraseña incorrectos, o falta libsasl2-modules. Corrige /etc/postfix/sasl_passwd, vuelve a ejecutar sudo postmap /etc/postfix/sasl_passwd y recarga Postfix. El host del archivo debe coincidir exactamente con relayhost, corchetes incluidos.

Connection timed out hacia el relay. El puerto 587 saliente está bloqueado. Compruébalo con nc -vz smtp.your_provider.com 587. Si falla, revisa el firewall de salida del servidor o usa el puerto alternativo que ofrezca tu proveedor.

Sender address rejected o 550 relacionado con el remitente. El proveedor no acepta la dirección de origen. Revisa /etc/postfix/generic, que el dominio coincida con System mail name (cat /etc/mailname) y que la dirección esté verificada en el proveedor.

Mensajes retenidos en la cola. Lista la cola con mailq. Tras corregir el problema, fuerza el reintento con sudo postqueue -f. Para descartar todo lo pendiente usa sudo postsuper -d ALL.

El correo llega a spam. Configura SPF, DKIM y DMARC del dominio remitente según las instrucciones de tu proveedor SMTP.

Conclusión

Tu servidor ya envía correo a través de un relay autenticado y cifrado, y te avisa cuando un disco se llena o un servicio de systemd falla. El mismo patrón sirve para cualquier otra comprobación: un script que solo escribe en mail cuando hay algo que contar, programado con cron o con un temporizador de systemd.

Como siguientes pasos puedes aplicar OnFailure= a tus servicios críticos (base de datos, servidor web, copias de seguridad), añadir un informe diario con la salida de df -h y systemctl --failed, o pasar a un sistema de monitorización como Prometheus con Alertmanager cuando gestiones varios servidores.