Cómo recibir un correo cuando un cron job falla
Actualizada el 1 de noviembre de 2026
Cron ya puede enviar correos: todo lo que imprime un job se envía a la dirección de MAILTO. En la práctica fallan tres cosas: el servidor no tiene cómo enviar correos, llega un correo por cada ejecución, y un job que falla sin imprimir nada no envía nada. Aquí verás cómo resolver cada una, y cómo avisar a un chat en su lugar.
Cómo funciona MAILTO
MAILTO=tu@example.com
0 3 * * * /ruta/a/backup.sh
- Cron envía por correo la salida de cada ejecución, tanto la salida estándar como los errores. Si el job no imprime nada, no hay correo.
-
MAILTOse aplica a las líneas que están debajo, hasta que otroMAILTOlo cambie.MAILTO=""desactiva los correos. -
Sin
MAILTO, el correo va al usuario del crontab en la misma máquina, a/var/mail/<usuario>, donde nadie lo lee.
Enviar los correos de cron por SMTP con msmtp
Cron entrega sus correos a /usr/sbin/sendmail, y la mayoría de los servidores no lo tienen. msmtp lo proporciona y envía los correos por una cuenta SMTP, la de tu proveedor de correo o la de un servicio como Amazon SES. En Debian y Ubuntu:
sudo apt install msmtp-mta
Escribe su configuración en el directorio personal del usuario del crontab, en ~/.msmtprc (para el crontab de root, /root/.msmtprc). Reemplaza host, port, from, user y password por los datos de tu proveedor:
defaults
auth on
tls on
syslog on
account default
host smtp.example.com
port 587
from cron@example.com
set_from_header on
user cron@example.com
password la-contraseña
chmod 600 ~/.msmtprc
-
fromes el remitente, la cuenta que envía los correos;MAILTO, en el crontab, es quien los recibe. Pueden ser la misma dirección. - El archivo tiene la contraseña, así que msmtp se niega a usarlo si otros usuarios pueden leerlo.
-
El puerto 587 con
tls onusa STARTTLS. Si tu proveedor usa el puerto 465, agregatls_starttls off. -
set_from_header onreemplaza el remitente que escribe cron, comoroot (Cron Daemon), por la dirección defrom. Muchos proveedores solo aceptan direcciones de tu cuenta. -
Con Gmail, el host es
smtp.gmail.comen el puerto 587, y la contraseña es una contraseña de aplicación, que requiere tener activada la verificación en dos pasos. -
syslog onregistra cada correo enviado o rechazado, y puedes leerlo conjournalctl -t msmtp.
Prueba primero msmtp, con el usuario del crontab:
printf 'Subject: prueba de msmtp\n\nFunciona.\n' | msmtp tu@example.com
Después prueba cron con una línea que imprima algo cada minuto, y bórrala cuando llegue el correo:
MAILTO=tu@example.com
* * * * * echo "prueba de correo de cron"
Otras distribuciones también tienen msmtp: cron solo necesita que /usr/sbin/sendmail sea msmtp u otro programa que envíe correos.
Solo cuando el job falla
Un job que imprime algo en cada ejecución envía un correo en cada ejecución, y pronto nadie los lee. Hay dos formas de recibirlos solo cuando el job falla.
Con chronic, de moreutils, que oculta la salida cuando el comando sale bien y la muestra cuando falla:
sudo apt install moreutils
MAILTO=tu@example.com
0 3 * * * chronic -v /ruta/a/backup.sh
chronic termina con el mismo código de salida que el job. Usa -v: sin esa opción, un job que falla sin imprimir nada no envía correo. Con ella, la salida llega con etiquetas y termina con RETVAL: y el código de salida, así que siempre se genera salida cuando el job falla, y cron tiene algo que enviar.
Sin chronic, guarda la salida en un archivo e imprímela, con el código de salida, solo cuando el job falla:
MAILTO=tu@example.com
0 3 * * * /ruta/a/backup.sh > /tmp/backup.log 2>&1 || { code=$?; echo "backup.sh falló con código $code"; cat /tmp/backup.log; }
Usa un archivo distinto para cada job, para que dos jobs no escriban en el mismo.
Por qué no llega el correo
-
El job no imprimió nada. Una ejecución que sale bien sin imprimir, o que falla sin imprimir nada, no tiene nada que enviar. Prueba con la línea del
echode arriba. -
No existe
/usr/sbin/sendmail. En Debian y Ubuntu, cron registraNo MTA installed, discarding output. Búscalo congrep CRON /var/log/syslogojournalctl -u cron(más en los logs de cron). -
msmtp no pudo enviarlo.
journalctl -t msmtpmuestra la respuesta del servidor SMTP: una contraseña incorrecta, un remitente rechazado, un puerto bloqueado. -
MAILTOno se aplica a la línea. Está debajo de la línea, está vacío, u otroMAILTOentre ambos lo cambia. - Llegó a spam. Revisa la carpeta de spam, y que el dominio del remitente tenga SPF y DKIM para el servidor que lo envía.
-
El job corre en un contenedor. Los contenedores rara vez tienen cómo enviar correos. Envía la salida a
docker logs(ver cómo ejecutar cron jobs en un contenedor Docker) o avisa a un chat, como se explica abajo.
Avisar a un chat en su lugar
Sin servidor de correo, la línea del crontab puede llamar a un webhook cuando el job falla. En estas líneas, || ejecuta la alerta solo si el job falla, y code=$? guarda primero el código de salida del job, para que el mensaje pueda incluirlo. Para un webhook entrante de Slack:
0 3 * * * /ruta/a/backup.sh || { code=$?; curl -fsS -m 10 -H 'Content-Type: application/json' -d "{\"text\":\"backup.sh falló en $(hostname) con código $code\"}" https://hooks.slack.com/services/...; }
Para un webhook de Discord, la misma línea con content en lugar de text:
0 3 * * * /ruta/a/backup.sh || { code=$?; curl -fsS -m 10 -H 'Content-Type: application/json' -d "{\"content\":\"backup.sh falló en $(hostname) con código $code\"}" https://discord.com/api/webhooks/...; }
Para una notificación en tu teléfono con ntfy, sin crear una cuenta:
0 3 * * * /ruta/a/backup.sh || { code=$?; curl -fsS -m 10 -H "Title: backup.sh falló" -d "En $(hostname), código $code" https://ntfy.sh/tu-tema; }
Para recibirla, instala la aplicación de ntfy en tu teléfono y suscríbete al mismo tema que pusiste en la URL (cómo hacerlo). Cualquiera que conozca un tema de ntfy.sh puede leerlo, así que elige un nombre largo y aleatorio.
Guarda el código con code=$? antes que nada, como en estas líneas: si el crontab usa bash (SHELL=/bin/bash), un $(hostname) escrito antes de $? en el mismo comando lo reinicia, y la alerta dice que el job falló con código 0.
Lo que estas alertas no pueden avisarte
El correo y el webhook los envía la misma línea, en la misma máquina, después del job. Si el job no se ejecuta, porque el servidor está caído, cron está detenido o alguien reemplazó el crontab, o si se cuelga y nunca termina, no hay correo ni mensaje. Para enterarte también de eso, necesitas un servicio que espere una señal del job dentro de un plazo y te avise cuando no llega (más en cómo monitorear cron jobs).
Con CronDrive
Reemplaza la línea por una que llame a CronDrive al inicio y al final, con el código de salida:
0 3 * * * curl -fsS -m 10 https://job.crondrive.com/<token>/start/$$; /ruta/a/backup.sh; curl -fsS -m 10 https://job.crondrive.com/<token>/end/$?/$$
CronDrive envía el correo sin que tu máquina necesite un servidor de correo, y también puede publicar en Slack, Discord, Microsoft Teams, Telegram o PagerDuty. Te avisa cuando el job falla, y también cuando no empieza o no termina en los minutos que permites. Cuando creas el job en CronDrive, te entrega esta línea con el token del job en lugar de <token>.