[philiptellis] /bb|[^b]{2}/
Never stop Grokking


Showing posts with label shell script. Show all posts
Showing posts with label shell script. Show all posts

Friday, January 29, 2010

Pretty print cron emails

We have a lot of scripts that run through cron and the output gets emailed by cron to whoever owns the cron job, or to a mailing list or something. Unfortunately, the headers for these mails are ugly and could use a lot of work. The primary problem I had with these mails was that the subject line could not be customised. Other smaller problems were that the From: address and Return-Path didn't have good values.

A sample header looks like this:
From: Cron Daemon <root@hostname.domain>
To: someone@somewhere.com
Subject: Cron <root@hostname> /usr/local/bin/foobar --whatever
Of the above, only the To: address makes any sense. The first thing I tried to change was the subject line. This is fairly easy using the mail program:
10 15 * * * /usr/local/bin/foobar --whatever | mail -s "Pretty subject" someone@somewhere.com
The mail now looks like this:
From: Cron Daemon <root@hostname.domain>
To: someone@somewhere.com
Subject: Pretty subject
This is a big step forward, because we can now filter emails based on subject. It still doesn't let us change the from address though. That's when I remembered using sendmail a long time ago to send mail through perl scripts, so I had a look through the sendmail man page, and found a few interesting flags:
-F full_name
       Set  the  sender full name. This is used only with messages that
       have no From: message header.

-f sender
       Set the envelope sender  address.  This  is  the  address  where
       delivery  problems  are  sent to, unless the message contains an
       Errors-To: message header.
This lets you set the From header, but there's no way to change the Subject. Since we can't use mail and sendmail together, we can either set the From address or the Subject, but not both. I then remembered the -t flag to sendmail that tells it to read the header from the message itself. The only thing left to do was to add the header into the output of every command. Since I couldn't easily do this in cron, I wrote my own script to do it. It's called pmail. The p is for pretty.

Get the script now

The meat of the script is this one line:
( echo -e "From: $from_name <$from>\r\nSubject: $subject\r\nTo: $to\r\n\r\n"; cat ) | /usr/sbin/sendmail -t
It writes the From and Subject headers, then leaves a blank line, and then passes its STDIN directly on to sendmail. The script has 3 optional parameters — the sender's address, sender's name and subject, and one mandatory parameter — the recipient's address(es).

To use it, set your cron line something like this:
* * * * * /usr/local/bin/foobar --whatever | \
   pmail -F "Philip Tellis" -f "philip@bluesmoon.info" -s "Pretty mail from foobar" someone@somewhere.com
Note: lines wrapped for readability.

You can also add the current date to the subject line like this:
... -s "Foobar mail on $( date +\%Y-\%m-\%d )" ...
Remember that you have to escape % signs in crontab lines otherwise cron will translate them to newline characters.

Umm, you also need to have sendmail set up correctly, and doing that is your problem :)

It's not complete yet, but it works for my use case. If you like it, use it. It's under the BSD license. I'll probably add a Reply-To option if it makes sense for me, and at some point add in data validation too, but not today.

Enjoy.

Friday, November 14, 2003

Self extracting tarball

install_tar.sh:
   #!/bin/bash

   skip=9
   # blah blah blah
   tail -n +$skip $0 | tar jxvf - | (while read a; do echo -n "."; done; echo;)

   exit
   __LINE_8_END_OF_CODE__

and then cat whatever.tar.bz2 >> install_tar.sh

voila, you have a self extracting tarball. Don't forget the exit just before the __LINE_8_END_OF_CODE__, and make sure that that *is* the last line of your shell code.

set skip to the line where your tar.bz2 data starts.

...===...