Outgoing Mail Analysis

First post is a handy mail script I have put together.
I’m using this to see how much mail I’m sending, which is necessary because I have a few WordPress sites on this machine and they seem to be pretty easy to hack. Using this script gives me an indication of outgoing mail volume.


Firstly I changed my mail.log to rotate daily instead of monthly so that when I’m investigating it I don’t need to worry about the date. The file will only have the info from yesterday.

So I removed “/var/log/mail.log” from the weekly rotation of /etc/logrotate.d/rsyslog and put it at the end of the file like this;

/etc/logrotate.d/rsyslog

/var/log/syslog
/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
    rotate 4
    weekly
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
            /usr/lib/rsyslog/rsyslog-rotate
    endscript
}
/var/log/mail.log {
    rotate 28
    daily
    missingok
    notifempty
    compress
    delaycompress
    postrotate
            /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

Next I created a new file “/usr/local/bin/ultimate_mail_audit.sh“. You can see I’m looking at “mail.log.1”. Since it gets rotated daily this is the log for yesterday.

/usr/local/bin/ultimate_mail_audit.sh

!/bin/bash
#=== CONFIGURATION ===
ADMIN_EMAIL="user@something.com,user2@something.com"
FROM_ADDRESS="info@localhost.com"
FROM_HEADER="From: Daily Outgoing Email Audit <$FROM_ADDRESS>"
MAIL_LOG="/var/log/mail.log.1"
TMP_REPORT="/tmp/mail_audit_$(date +%F_%H-%M-%S).txt"
TMP_QUEUE_MAP="/tmp/queueid_to_user.$$"
TMP_MAIL_SUMMARY="/tmp/mail_summary.$$"

touch "$TMP_REPORT" "$TMP_QUEUE_MAP" "$TMP_MAIL_SUMMARY"

#--- HEADER ---
{
echo "Legitimate Outgoing Mail Summary:"
echo "____________________________"
} >> "$TMP_REPORT"

#--- Step 1: Map queue IDs to authenticated SASL usernames ---
grep "sasl_username=" "$MAIL_LOG" | while read -r line; do
    queue_id=$(echo "$line" | grep -oE '[A-F0-9]{10,}')
    user=$(echo "$line" | grep -oP 'sasl_username=\K\S+')
    [[ -n "$queue_id" && -n "$user" ]] && echo "$queue_id:$user"
done >> "$TMP_QUEUE_MAP"

#--- Step 2: Map queue IDs to local pickup user IDs ---
grep 'postfix/pickup' "$MAIL_LOG" | grep -oP '([A-F0-9]{10,}): uid=\K\d+' | while read -r uid; do
    queue_id=$(grep "uid=${uid}" "$MAIL_LOG" | grep -oE '[A-F0-9]{10,}')
    user=$(getent passwd "$uid" | cut -d: -f1)
    [[ -n "$queue_id" && -n "$user" ]] && echo "$queue_id:$user"
done >> "$TMP_QUEUE_MAP"

#--- Step 3: Extract legit outgoing emails ---
grep 'status=' "$MAIL_LOG" | grep 'postfix/' | grep -v 'relay=local' | while read -r line; do
    queue_id=$(echo "$line" | awk '{print $6}' | sed 's/://')
    to=$(echo "$line" | grep -oP 'to=<\K[^>]+')
    from=$(grep "$queue_id" "$MAIL_LOG" | grep 'from=<' | head -n1 | grep -oP 'from=<\K[^>]+')
    user=$(grep "^${queue_id}:" "$TMP_QUEUE_MAP" | cut -d: -f2)
    if [[ -n "$user" && -n "$from" && -n "$to" ]]; then
        echo "$from -> $to"
    fi
done | sort | uniq -c | sort -nr >> "$TMP_MAIL_SUMMARY"

#--- Step 4: Output to report ---
cat "$TMP_MAIL_SUMMARY" >> "$TMP_REPORT"

#--- Step 5: Email and cleanup ---
mail -a "$FROM_HEADER" -r "$FROM_ADDRESS" -s "Daily Email Audit - $(hostname)" "$ADMIN_EMAIL" < "$TMP_REPORT"
rm -f "$TMP_QUEUE_MAP" "$TMP_MAIL_SUMMARY" "$TMP_REPORT"

Now we need a cronjob to run this script. So run “crontab -e” and put this in there

30 7 * * * /usr/local/bin/ultimate_mail_audit.sh

I’m running this on;

SYSTEM INFORMATION
OS type and versionUbuntu Linux 22.04.5
Usermin version2.302
Virtualmin version7.30.8
Theme version24.02
Apache version2.4.52
Package updatesAll installed packages are up to date


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *