Here's how I do it:
In this scenario I have 4 databases (dumps) I need to backup and if everything went normal I want to receive an email mentioning so. If I had errors I want a message with a different subject to point it out, the failed database included in the message body and the error log attached to the email.
The first file (/root/templates/ylatis-backup.txt) is just a message body template:
Backup status report from: %hostname
Network configuration:
%net_config
Database backups:
ylatis-cy :%cy_status
ylatis-ug :%ug_status
ylatis-rw :%rw_status
ylatis-lc :%lc_status
All words prefixed by % are treated as variables and replaced by sed later on in the script.
%hostname and %net_config are used to identify which computer the email is coming from.
The variables ending in _status are replaced with the word NORMAL or ERROR so I can know what went wrong.
#!/bin/bash
NET_CONFIG=$(ifconfig |grep inet |grep -v inet6 |grep -v '127.0.0.1')
MESSAGE_TEMPLATE=/root/templates/ylatis-backup.txt
REPORT_FILE=/tmp/bkup-report-$$.txt
MESSAGE=$(cat $MESSAGE_TEMPLATE)
MAIL_FROM='no-reply@hostname.com'
MAIL_TO='user@hostname.com'
MAIL_SUBJECT="[$HOSTNAME] [Backup Report: Databases] %status [$(date +%Y-%m-%d)]"
MAIL_SERVER='smtp.gmail.com:587'
MAIL_USER='no-reply@hostname.com'
MAIL_PASS='**********'
CY_ERR=/tmp/ylatis-cy_err.$$
UG_ERR=/tmp/ylatis-ug_err.$$
RW_ERR=/tmp/ylatis-rw_err.$$
LC_ERR=/tmp/ylatis-lc_err.$$
ERROR_LOG=/tmp/error_log-$$.txt
MESSAGE=$(echo "$MESSAGE" |sed 's@%hostname@'"$HOSTNAME"'@g')
MESSAGE=$(echo "$MESSAGE" |sed 's@%net_config@'"$NET_CONFIG"'@g')
mount -a
rsync -azv --chown root:root lp@10.10.10.14::backup/ /mnt/hdd3/ylatis-cy/ 1>/dev/null 2>$CY_ERR
cy_status=$?
rsync -azv --chown root:root lp@10.10.10.10::ylatisug/ /mnt/hdd3/ylatis-ug/ 1>/dev/null 2>$UG_ERR
ug_status=$?
rsync -azv --chown root:root lp@10.10.10.10::ylatisrw/ /mnt/hdd3/ylatis-rw/ 1>/dev/null 2>$RW_ERR
rw_status=$?
rsync -azv --chown root:root lp@10.10.10.10::labco/ /mnt/hdd3/ylatis-labco/ 1>/dev/null 2>$LC_ERR
lc_status=$?
if [ $cy_status -eq 0 ] && [ $ug_status -eq 0 ] && [ $rw_status -eq 0 ] && [ $lc_status -eq 0 ]; then
##########
#ALL GOOD#
##########
MAIL_SUBJECT=$(echo "$MAIL_SUBJECT" |sed 's@%status@[NORMAL]@g')
MESSAGE=$(echo "$MESSAGE" |sed 's@%cy_status@NORMAL@g')
MESSAGE=$(echo "$MESSAGE" |sed 's@%ug_status@NORMAL@g')
MESSAGE=$(echo "$MESSAGE" |sed 's@%rw_status@NORMAL@g')
MESSAGE=$(echo "$MESSAGE" |sed 's@%lc_status@NORMAL@g')
echo "$MESSAGE" >$REPORT_FILE
sendemail -f $MAIL_FROM -t $MAIL_TO -u $MAIL_SUBJECT -o message- file=$REPORT_FILE -s $MAIL_SERVER -xu $MAIL_USER -xp $MAIL_PASS
else
################
#ERRORS OCCURED#
################
MAIL_SUBJECT=$(echo "$MAIL_SUBJECT" |sed 's@%status@[ERROR]@g')
if [ $cy_status -eq 0 ]; then
MESSAGE=$(echo "$MESSAGE" |sed 's@%cy_status@NORMAL@g')
else
MESSAGE=$(echo "$MESSAGE" |sed 's@%cy_status@ERROR@g')
fi
if [ $ug_status -eq 0 ]; then
MESSAGE=$(echo "$MESSAGE" |sed 's@%ug_status@NORMAL@g')
else
MESSAGE=$(echo "$MESSAGE" |sed 's@%ug_status@ERROR@g')
fi
if [ $rw_status -eq 0 ]; then
MESSAGE=$(echo "$MESSAGE" |sed 's@%rw_status@NORMAL@g')
else
MESSAGE=$(echo "$MESSAGE" |sed 's@%rw_status@ERROR@g')
fi
if [ $lc_status -eq 0 ]; then
MESSAGE=$(echo "$MESSAGE" |sed 's@%lc_status@NORMAL@g')
else
MESSAGE=$(echo "$MESSAGE" |sed 's@%lc_status@ERROR@g')
fi
echo "$MESSAGE" >$REPORT_FILE
cat /dev/null >$ERROR_LOG
find /tmp/ -name \*.$$ -exec cat {} \; >>$ERROR_LOG
cp $ERROR_LOG .
sendemail -f $MAIL_FROM -t $MAIL_TO -u $MAIL_SUBJECT -o message-file=$REPORT_FILE -a error_log-$$.txt -s $MAIL_SERVER -xu $MAIL_USER -xp $MAIL_PASS
rm error_log-$$.txt
fi
#Cleanup
rm /tmp/*.$$ 2>/dev/null
rm /tmp/*$$.txt 2>/dev/null
Note how I am monitoring the exit status of rsync to determine what the message and subject of my email should be. In my case I am discarding normal output (1>/dev/null) and keeping only the standard error output (2>$error_log). You could just use the >> operator if you want to keep all the output. You could also adjust to include the log in the message instead of an attachment for convenience if you are reading your mail from terminal.
Maybe it looks like an overkill to a relatively simple question but I think it outlines well what you are trying to do. You need to build your message while running your command through an intermediate script and send it later. If you find the above code useful and have any questions on it feel free to ask in comments.