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
- Reverse DNS and forward DNS for every sending address (How to set reverse DNS (PTR) for many IP addresses and check forward-confirmed rDNS?).
- That each address can still open a connection to port 25 of another mail server (How to check that outgoing port 25 works from your dedicated server?).
- The number of queued and deferred messages.
- The share of deferred and bounced deliveries in the last hour.
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
- Google Postmaster Tools for spam rate and domain reputation (How to test authentication and deliverability of your outgoing email?).
- The status of your addresses on public blocklists, checked at times (How to check whether a new IP address is on a blocklist before you use it?).
- Complaint reports from Yahoo and Microsoft programmes (How to process bounces and spam complaints and keep a suppression list?).
What to do when an alert arrives
- DNS alert: fix the record. Reverse DNS is changed in the client area.
- Port 25 alert: test from another address and ask support if the connection stays blocked.
- 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.
- 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?
- Unmanaged dedicated servers: full root access and IPv4 subnets from /29 up to /24, ordered with the server or added later.
- Managed dedicated servers: our team looks after the operating system, updates, security and monitoring.
- Dedicated server locations: choose the country and data centre when you order.
Prefer a hand with the setup? Our engineers can do it for you: Hire an Expert, or use our on-demand server management.
