#!/bin/bash export LC_ALL=en_US.utf8 MAILLOG=/var/log/mail.log LOGMAILFROM="Your sender name" ## Set the FROM for the e-mail. You can write "Bounce Mail Report" LOGMAILTO="your@yourdomain.tld" ## Set the TO for the e-mail (single e-mail address). TIME_START=$(date +"%s") ALLBOUNCES=`cat ${MAILLOG} |egrep "$(date -d '-1 hour' '+%b %e %H').*postfix/smtp.*status=bounced"` COUNTBOUNCES=$( [ -n "$ALLBOUNCES" ] && echo "$ALLBOUNCES" | wc -l || echo 0 ) if [ ${COUNTBOUNCES} -gt 0 ]; then MAILINFO='' MAILINFO+='' MAILINFO+='' MAILINFO+="" while IFS= read -r BOUNCE do ## Clean the bounce variable (remove all line-breaks) BOUNCE="${BOUNCE//$'\n'/ }" ## Get the mail ID from the current log line MAILID=$(perl -pe "s/.*?postfix\/smtp\[\w+\]:\s(\w+).*/\1/g" <<< ${BOUNCE}) MAILTO=$(perl -pe "s/.*to=<(.*?)>.*/\1/g" <<< ${BOUNCE}) DATETIME=$(perl -pe "s/^(\w+\s+\w+\s+\w+:\w+:\w+)\s.*/\1/g" <<< ${BOUNCE}) ## Check if there's information about the host (there is non when the delivery has been done locally) NEEDLE=".*?\(host\s.*?\[.*" if [[ "${BOUNCE}" =~ ${NEEDLE} ]]; then HOST=$(perl -pe "s/.*?\(host\s(.*?)\[.*/\1/g" <<< ${BOUNCE}) HOSTIP=$(perl -pe "s/.*?\(host\s.*?\[(.*?)\]\s.*/\1/g" <<< ${BOUNCE}) else HOST="No host found" HOSTIP="No IP found" fi ## Try to fetch the bounce reason NEEDLE=".*\ssaid:\s.*" if [[ "${BOUNCE}" =~ ${NEEDLE} ]]; then REASON=$(perl -pe "s/.*\ssaid:\s(.*)/\1/g" <<< ${BOUNCE}) else ## Check if perhaps the domain could not be resolved (Host not found message). In that case there would be no said NEEDLE=".*\(Host or domain name not found.*" BOUNCE_MSG_PRESENT=".*?status=bounced\s\(.*" if [[ "${BOUNCE}" =~ ${NEEDLE} ]]; then REASON=$(perl -pe "s/.*?\((Host or domain name not found.*)/\1/g" <<< ${BOUNCE}) elif [[ "${BOUNCE}" =~ ${BOUNCE_MSG_PRESENT} ]]; then REASON=$(perl -pe "s/.*?status=bounced\s\((.*?)\)/\1/g" <<< ${BOUNCE}) else REASON="Reject reason not found." fi fi ## Fetch additional information about the bounced message based on the MAILID MESSAGEDATA=$(cat ${MAILLOG} |grep ${MAILID}) MESSAGEDATA="${MESSAGEDATA//$'\n'/ }" ## Check if there's a username NEEDLE=".*sasl_username.*" if [[ "${MESSAGEDATA}" =~ ${NEEDLE} ]]; then USERNAME=$(perl -pe "s/.*?sasl_username=(.*?)\s.*/\1/gm" <<< ${MESSAGEDATA}) SASL_CLIENT_PTR=$(perl -pe "s/.*?client=(.*?)\[.*/\1/gm" <<< ${MESSAGEDATA}) SASL_CLIENT_IP=$(perl -pe "s/.*?client=.*?\[(.*?)\].*/\1/gm" <<< ${MESSAGEDATA}) else USERNAME="local delivery (non-delivery notification)" SASL_CLIENT_PTR="No PTR found" SASL_CLIENT_IP="No IP found" fi ## Check if there's a subject line NEEDLE=".*?header\sSubject:\s.*?\sfrom\s.*" if [[ "${MESSAGEDATA}" =~ ${NEEDLE} ]]; then SUBJECT=$(perl -pe "s/.*?header\sSubject:\s(.*?)\sfrom\s.*/\1/gm" <<< ${MESSAGEDATA}) else NEEDLE=".*sender non-delivery notification.*" if [[ "${MESSAGEDATA}" =~ ${NEEDLE} ]]; then SUBJECT="No subject (delivery notification)" else SUBJECT="No subject (reason unknown)" fi fi MAILFROM=$(perl -pe "s/.*?from=<(.*?)>.*/\1/gm" <<< ${MESSAGEDATA}) MAILINFO+="" done <<< "$ALLBOUNCES" MAILINFO+="
DATE & TIMEMAIL IDCLIENT PTRCLIENT IPUSERNAMEMAIL FROMMAIL TOHOSTHOST IPREASONSUBJECT
${DATETIME}${MAILID}${SASL_CLIENT_PTR}${SASL_CLIENT_IP}${USERNAME}${MAILFROM}${MAILTO}${HOST}${HOSTIP}${REASON}${SUBJECT}
" MAILINFO+="

Additional information

" MAILINFO+="" TIME_DIFF=$(($(date +"%s")-${TIME_START})) MAILINFO+="" MAILINFO+="
Script runtime:$((${TIME_DIFF} / 60)) Minutes$((${TIME_DIFF} % 60)) Seconds
" if [ ${COUNTBOUNCES} -gt 6 ]; then BOUNCEWARNING="WARNING | "; else BOUNCEWARNING=""; fi echo ${MAILINFO} | mail -a "From: ${LOGMAILFROM}" -a "MIME-Version: 1.0" -a "Content-Type: text/html; charset=utf-8" -s "${BOUNCEWARNING}${COUNTBOUNCES} Mail Bounce(s) Registered" ${LOGMAILTO} fi