How can I only receive emails from cron if there are errors?

In the overwhelmingly vast majority of cases, the tasks will run just fine - and I truly do not care about the output.

It is only in the rare case of a failure that I want/need to know.

I have procmail available - but am not sure if what I'm describing is possible to manage externally to cron "correctly".

  • 1
    What if crond itself isn't running? Or the machine is offline? That's why I never bother with emails from cron and use a dedicated cron monitoring service. I'm partial to WDT.io and recommend it. – Christian Pekeler Jun 20 '17 at 5:23

As you are not caring for the output, you can redirect the STDOUT of a job to /dev/null and let the STDERR being send via mail (using MAILTO environment variable).

So, for example:

* * * * * /my/script.sh >/dev/null

will send mail when there is output only on STDERR (with the STDERR), and will discard the STDOUT.

This of course assumes that when a program has written on STDERR, has failed; this might not be always the case. If you have control over the program, you can make it do so. For any complex case, you should write a wrapper of some kind that runs the command(s) and send mail accordingly. And put the wrapper as the cron job.

  • 1
    The downside of this approach is when it fails you only get the STDERR output which may make diagnosis harder than if you had the full output. – plugwash Jun 20 '17 at 14:24

The chronic command from moreutils runs a command quietly unless it fails.

Quoting from its manual:

chronic runs a command, and arranges for its standard out and standard error to only be displayed if the command fails (exits nonzero or crashes). If the command succeeds, any extraneous output will be hidden.

A common use for chronic is for running a cron job. Rather than trying to keep the command quiet, and having to deal with mails containing accidental output when it succeeds, and not verbose enough output when it fails, you can just run it verbosely always, and use chronic to hide the successful output.


How can I only receive emails from cron if there are errors?

You could wrap your cron invocations with cronic, a shell script which eats cron output unless the return code of the invoked process is non-zero or there is non-trace error output.

To use cronic, download the script to a suitable location, such as /usr/local/bin. Your crontab entries must be prefixed with the path to the script (e.g. /usr/local/bin/cronic), or simply cronic, provided your PATH is set properly.

Do note that "errors" is an ill-defined term in your question and requires careful definition. For cronic to be useful, you must ensure the jobs you wrap with cronic report errors in one of the ways it defines an error condition. Implicit methods of reporting, such as writing text strings to STDOUT, will require further thought to make this compatible with cronic or another cron reporting mechanism.

Other wrappers are available, as linked from the cronic site:

  • 1
    Is cronic related to chronic, or is that just coincidence? – Toby Speight Jun 20 '17 at 14:25
  • @TobySpeight Coincidence it seems. cronic is implemented in bash, chronic as suggested in the earlier answer is a Perl script. – Cosmic Ossifrage Jun 20 '17 at 23:07

Here is another variation that I've successfully utilized for many years - capture output and print it out only on error. This requires no temp files, and preserves all output. The important part is the 2>&1 that redirects STDERR to STDOUT.

Send the entire output via default cron mailer config:

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || echo "$OUTPUT"

Same but with a specific address and subject:

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || echo "$OUTPUT" | mail -s "Failed to backup" an@email.address

You can even perform multiple actions on error and add to email:

1 2 * * * root OUTPUT=`flexbackup -set all 2>&1` || {echo "$OUTPUT" ; ls -ltr /backup/dir ; }

This will work for simple commands. If you are dealing with complex pipes (find / -type f | grep -v bla | tar something-or-other), then you're better off moving the command into a script and running the script using the aforementioned approach. The reason is that if any part of the pipe outputs to STDERR, you'll still get emails.

  • You should put $OUTPUT in quotes: "$OUTPUT". – G-Man Says 'Reinstate Monica' Nov 30 '18 at 13:58
  • @G-Man Fair point, there is always a chance that the output may contain "-n" or something similar. – Akom Dec 1 '18 at 14:02

I have probably not thought this all the way through, but

* * * * * yourthing.sh >/tmp/yourthing.log && rm -f /tmp/yourthing.log; cat /tmp/yourthing.log 2>/dev/null

would, in ordinary cases, redirect everything to a temporary file (you probably would want to use mktemp to obtain a unique filename), delete that if the file was successful, and then cat the contents again, if they still exist (i.e. yourthing.sh exited with error condition), to be picked up by the cron mailer.

If memory serves, cron already does not send anything if there was no output, so if the log file is empty or does not exist, nothing happens. (We redirect the error message away.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.