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.
NotaMuchos proveedores cloud bloquean el tráfico saliente al puerto 25 para evitar spam. Por eso esta guía no entrega el correo directamente, sino que lo envía a un servidor SMTP autenticado en el puerto 587, que es la forma fiable de que tus alertas no acaben en la carpeta de spam.
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 = encryptobliga a usar STARTTLS, de modo que la contraseña nunca viaja sin cifrar.inet_interfaces = loopback-onlyhace 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
NotaSi usas Gmail, el relay es
[smtp.gmail.com]:587y la contraseña debe ser una contraseña de aplicación (requiere tener activada la verificación en dos pasos). Gmail reescribe el remitente a tu cuenta de Google en cualquier caso.
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]
Nota
bsd-mailxno adjunta archivos (su opción-aañade cabeceras). Para alertas basta con incluir el texto relevante en el cuerpo del mensaje, como harás en los pasos siguientes.
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.
