Updated: 28 September 2026 · Applies to: Postfix 3.8 (Ubuntu 24.04) and 3.10 (Ubuntu 26.04) on Ubuntu 24.04 and 26.04 LTS

Mail problems grow quietly: a wrong DNS record, a queue that fills up, a rising bounce rate. A small script that checks your sending addresses every 15 minutes and mails you when something looks wrong is worth setting up on day one. This guide provides one. It only reports; you decide what to do, using How to read Postfix logs and understand common SMTP error codes? and What to do when your IP address is on a blocklist or your mail is rejected?.

What it checks

1. The list of addresses

Create /etc/mailmon.conf, one line per sending address with its host name:

203.0.113.10 mail1.example.com
203.0.113.11 mail2.example.com
203.0.113.12 mail3.example.com

2. The script

Save it as /usr/local/bin/mailmon.sh:

#!/bin/bash
# Reports problems with sending addresses. Change these values:
ALERT_TO="admin@example.com"
QUEUE_MAX=2000          # alert if more messages wait in the queue
DEFER_PCT=20            # alert if more than 20 percent of deliveries were deferred
BOUNCE_PCT=5            # alert if more than 5 percent were bounced
TEST_HOST="gmail-smtp-in.l.google.com"

problems=""
add() { problems="$problems$1\n"; }

# 1. DNS and port 25 for each address
while read -r ip name; do
  [ -z "$ip" ] && continue
  ptr=$(dig -x "$ip" +short | head -1 | sed 's/\.$//')
  if [ "$ptr" != "$name" ]; then add "$ip: PTR is '$ptr', expected '$name'"; fi
  if ! dig +short A "$name" | grep -qw "$ip"; then add "$ip: A record of $name does not point to it"; fi
  if ! nc -s "$ip" -z -w 10 "$TEST_HOST" 25 2>/dev/null; then add "$ip: cannot connect to port 25 of $TEST_HOST"; fi
done < /etc/mailmon.conf

# 2. Queue size
queued=$(postqueue -j 2>/dev/null | wc -l)
if [ "$queued" -gt "$QUEUE_MAX" ]; then add "Queue has $queued messages"; fi

# 3. Delivery results of the last hour
log=$(journalctl -t postfix/smtp --since "1 hour ago" --no-pager 2>/dev/null | grep "status=")
sent=$(echo "$log" | grep -c "status=sent")
deferred=$(echo "$log" | grep -c "status=deferred")
bounced=$(echo "$log" | grep -c "status=bounced")
total=$((sent + deferred + bounced))
if [ "$total" -ge 50 ]; then
  [ $((deferred * 100 / total)) -gt "$DEFER_PCT" ] && add "Deferred: $deferred of $total in the last hour"
  [ $((bounced * 100 / total)) -gt "$BOUNCE_PCT" ] && add "Bounced: $bounced of $total in the last hour"
fi

if [ -n "$problems" ]; then
  printf "$problems" | mail -s "Mail check on $(hostname): problems found" "$ALERT_TO"
fi

Make it executable: sudo chmod +x /usr/local/bin/mailmon.sh. Run it once by hand to test: sudo /usr/local/bin/mailmon.sh. It prints nothing when all is well.

The percentages are examples; adapt them to your own normal values. Providers care about bounce and complaint numbers, so track them over time (How to process bounces and spam complaints and keep a suppression list?).

3. Run it every 15 minutes

echo '*/15 * * * * root /usr/local/bin/mailmon.sh' | sudo tee /etc/cron.d/mailmon

Alerts are sent through your own Postfix. If Postfix itself is the problem you may not get the alert; for important servers send the alert through a second channel, for example an external mailbox and a monitoring service that checks your server from outside. Ucartz offers server monitoring services for this.

What else to watch by hand

What to do when an alert arrives

  1. DNS alert: fix the record. Reverse DNS is changed in the client area.
  2. Port 25 alert: test from another address and ask support if the connection stays blocked.
  3. Queue or deferral alert: read the log text, slow down (How to set delivery rate limits per provider in Postfix and handle deferrals?), do not add more traffic.
  4. Bounce alert: stop the campaign, look at the list and the bounce text.

Frequently asked questions

Can the script switch off an address automatically?
It is better that a person decides. A wrong automatic action can stop mail that is fine, and moving the same mail to other addresses only spreads a problem (What to do when your IP address is on a blocklist or your mail is rejected?).

Does the script work on other Linux systems?
The commands are standard. The log query uses journalctl; on systems that write /var/log/mail.log, replace it with grep on that file.

Need a dedicated server, more IP addresses, or a hand with the setup?

Prefer a hand with the setup? Our engineers can do it for you: Hire an Expert, or use our on-demand server management.

Was this answer helpful? 0 Users Found This Useful (0 Votes)