Cron Job MAILTO: Correct Syntax and Why It Fails
September 12, 2026


What Is MAILTO in a Cron Job?
MAILTO is a crontab environment variable that tells crond where to email a job's output. When a scheduled task writes anything to stdout or stderr, cron captures it and, instead of discarding it, mails it to whatever address MAILTO points to. It's not a shell variable and it doesn't belong in your script — it has to be declared inside the crontab file itself, on its own line, above the jobs it should apply to.
This distinction trips people up constantly. Setting export MAILTO=you@example.com in a bash script does nothing for cron; the scheduler reads its own crontab environment, separate from whatever shell context your script runs in. The cron job mailto setting only works when it lives in the crontab, either the user's personal crontab (edited with crontab -e) or a system-wide file like /etc/crontab.
Think of MAILTO as a notification pipe, not a monitoring system. It reports what a job printed, not whether the job succeeded, ran on schedule, or ran at all. That gap matters more than most tutorials admit, and we'll come back to it.
MAILTO Syntax and Examples
The crontab email variable syntax is simple, but small mistakes break it silently. Place it before the job lines it should govern:
MAILTO=you@example.com
0 3 * * * /usr/local/bin/backup.sh
Every job below that line, until MAILTO is redefined, sends output to that address. For multiple email addresses, separate them with commas and no spaces:
MAILTO=alice@example.com,bob@example.com
0 3 * * * /usr/local/bin/backup.sh
Quoting rarely helps and sometimes hurts — some cron implementations treat quote characters literally rather than stripping them, so MAILTO="you@example.com" may end up mailing a malformed address. Stick to the bare, unquoted form.
To suppress cron email notifications for a specific job without deleting it, set MAILTO to an empty string:
MAILTO=""
0 3 * * * /usr/local/bin/backup.sh
If MAILTO is left unset entirely, cron falls back to mailing the crontab owner's local system account — not necessarily an address anyone actually checks. On most distributions that mail is delivered locally and never leaves the machine unless a mail transfer agent is configured to relay it out. The crontab(5) manual page documents this default behavior precisely, along with the related MAILFROM variable, which lets you override the sender address on systems where the local mailer supports it.
Why MAILTO Often Fails to Send Email
This is where most cron job mailto guides stop short, and where developers actually lose sleep. Setting MAILTO doesn't guarantee delivery — it just tells cron where to try sending mail, using whatever mail transfer agent is installed locally. If there is no MTA at all — no sendmail, no Postfix, no ssmtp configured — cron has literally nothing to hand the message to, and it disappears with no error, no log entry, no retry.
Even when an MTA exists, root's mail is frequently never forwarded anywhere. Local mail for root piles up in /var/mail/root unless /etc/aliases (or a .forward file) redirects it externally, and nobody logs into a headless server to read a local mailbox. This is one of the most common reasons crontab MAILTO not working reports turn out to be "it worked exactly as configured" — the mail just went into a black hole nobody checks.
Other common culprits:
- Output redirection eats the message before cron sees it. If your job already redirects stdout and stderr to
/dev/nullor a log file, there's no output left for cron to mail — MAILTO has nothing to act on, regardless of how it's configured. - A single syntax error anywhere in the crontab can silently break the whole file on some cron implementations, meaning even unrelated jobs stop running or stop mailing, with no obvious signal beyond the missing job history.
- Spam filtering swallows the message. Mail sent from a server's default hostname, with no SPF/DKIM setup, gets flagged or dropped by major providers long before it reaches an inbox.
If you're troubleshooting cron mail issues, checking /var/log/mail.log or mail -f /var/mail/root locally will tell you more in five minutes than guessing at crontab syntax.
MAILTO vs. Redirecting Output Yourself
An alternative to relying on cron's built-in mailer is handling notification inside the script: redirect stdout/stderr explicitly, capture the exit code, and call your own mail or webhook command when something fails. This gives you control over formatting, conditional alerts (only email on non-zero exit, for instance), and independence from crontab-level MAILTO quirks.
The tradeoff is that you still need something capable of sending mail — curl to an API, a configured sendmail binary, or a transactional email service — so you haven't eliminated the dependency on working infrastructure, just moved it. It does make behavior more portable across cron implementations, since you're no longer relying on crond's mail-handling defaults, which vary by distribution. For a deeper look at structuring scripts so output and errors are handled deliberately rather than accidentally, see how to write a cron job script that runs correctly.
The Real Limitation: MAILTO Can't Tell You a Job Didn't Run
Here's the structural problem no amount of correct MAILTO syntax fixes: the mail-on-output mechanism only fires when the job executes and produces something to report. It says nothing if cron itself never triggered, if the server was rebooting during the scheduled window, if the script hung indefinitely without erroring, or if the mail queue silently dropped the message after accepting it.
A cron job that fails silently — never starts, hangs, or gets killed by an OOM reaper — leaves no output, no error, and therefore no email, even with MAILTO configured perfectly. From the outside, "no news" looks identical whether the job succeeded quietly or never ran at all. Answering "did this job actually run?" requires something watching from outside the process, not a notification that depends on the process behaving.
That's the gap HTTP-based monitoring closes: a scheduled job pings a monitoring endpoint on success, and if that ping doesn't arrive within the expected window, you get alerted — regardless of whether the failure was an error, a hang, a dead server, or a broken mail relay. For a closer look at verifying execution rather than just output, see checking cron job status to confirm it actually ran and succeeded, and consult the Baeldung guide on crontab email notifications for more MAILTO configuration examples.
MAILTO can tell you a job ran and printed something. It can't tell you a job never started, that the server rebooted mid-schedule, or that the mail queue quietly swallowed the message. Cronevra closes that gap with HTTP-based heartbeat monitoring that doesn't depend on a local mail stack at all — check the pricing page if you're ready to stop guessing whether your cron jobs actually ran.