Your mail queue is growing with bounces to envelope senders at domains you have never heard of. Within hours, your IP lands on a DNSBL and legitimate mail stops reaching its destination.

This is a backscatter storm. Postfix accepted mail for recipients it could not deliver to, then generated non-delivery reports (NDRs) to the forged envelope sender. Those NDRs hit innocent third parties whose addresses the spammer forged.

The fix: reject unknown recipients at SMTP time instead of accepting and bouncing later. The challenge is identifying which misconfiguration let the mail through, stopping the storm without losing legitimate mail, and repairing your sender reputation.

What this means

Backscatter happens when Postfix acts as a backup MX, relay, or gateway that accepts mail without validating recipients against a known-good list. The message is accepted during the SMTP transaction, queued, delivery fails, and Postfix generates a bounce to the forged envelope sender.

If the bounce destination is also invalid, Postfix generates a double-bounce. Double-bounces are discarded by default, but the processing load consumes cleanup, bounce, and queue manager resources. Meanwhile, the original bounces to forged addresses are actively damaging your sender reputation.

Key signals: a bounce rate spike followed by sustained elevated injection, maildrop queue activity from local bounce generation, and queue entries from MAILER-DAEMON or double-bounce senders.

flowchart LR
    A["Spammer sends with\nforged return path"] --> B["Your Postfix accepts\nfor unknown recipient"]
    B --> C["Delivery fails:\nuser unknown"]
    C --> D["Bounce generated\nto forged sender"]
    D --> E["Innocent third party\nreceives NDR spam"]
    D --> F["Forged address invalid?\nDouble-bounce discarded"]
    E --> G["Complaints and\nDNSBL listing"]

The critical distinction: rejecting at SMTP time (5xx response during RCPT TO) produces no bounce. The connecting server is responsible for generating any NDR. Accepting then failing produces a bounce from your server, making you the source of backscatter.

Common causes

CauseWhat it looks likeFirst thing to check
Backup MX without relay_recipient_mapsMail accepted for any address in relay domains, then bounced after delivery failurepostconf -h relay_recipient_maps
Wildcard catch-all aliasAll mail to a domain accepted regardless of recipient validity, then bounced or forwarded to nonexistent addressesCheck virtual alias maps for @domain wildcard entries
Empty local_recipient_maps with luser_relayLocal recipients not validated before acceptance; all mail redirected via luser_relaypostconf -h local_recipient_maps luser_relay
relay_recipient_maps configured with @domain wildcardPostfix accepts mail for any recipient in relay domains, becoming a backscatter source per Postfix documentationInspect relay recipient map contents for wildcard entries
Content filter accepting then rejectingFilter passes SMTP but rejects during processing, generating late bouncesCheck content_filter logs for post-acceptance rejections

Quick checks

These commands are read-only and safe to run during an active incident. Your log path may be /var/log/maillog (RHEL family) instead of /var/log/mail.log (Debian family). Adjust accordingly.

# Count bounces logged in the current hour
grep "$(date '+%b %e %H')" /var/log/mail.log | grep -c 'status=bounced'

# Count MAILER-DAEMON messages currently queued
postqueue -p | grep -c 'MAILER-DAEMON'

# Show top senders in the queue (Postfix 3.1+ uses -j JSON output)
postqueue -j | jq -r '.sender' | sort | uniq -c | sort -rn | head -20

# Identify forged sender patterns in recent bounces
grep 'status=bounced' /var/log/mail.log | tail -20 | grep -o 'from=<[^>]*>' | sort | uniq -c

# Inspect bounce destination domains
grep 'status=bounced' /var/log/mail.log | grep -oE 'to=<[^>]*>' | cut -d@ -f2 | sort | uniq -c | sort -rn | head

# Check if relay_recipient_maps is configured
postconf -h relay_recipient_maps

# Check if local_recipient_maps is populated
postconf -h local_recipient_maps

# Check recipient rejection enforcement
postconf -h smtpd_reject_unlisted_recipient

# Check current deferred queue size
find /var/spool/postfix/deferred -type f | wc -l

# Check inode usage on queue filesystem (backscatter consumes inodes fast)
df -i /var/spool/postfix

How to diagnose it

  1. Confirm backscatter is happening. Look for bounces (status=bounced) with sender addresses at domains unrelated to your users or relay customers. If the log fills with MAILER-DAEMON mail to random external domains, you are generating backscatter.

  2. Identify which mail was accepted that should have been rejected. Search for recent bounced messages:

    grep 'status=bounced' /var/log/mail.log | tail -50
    

    Look at the to=<...> field. If the recipient does not exist in your directory, the message should have been rejected at SMTP time, not accepted and bounced.

  3. Trace the acceptance path. Check which Postfix restriction allowed the message through. Determine whether the recipient domain is in relay_domains, mydestination, or virtual_alias_domains:

    postconf -h relay_domains mydestination virtual_alias_domains
    

    Then check whether the corresponding recipient validation map exists and is populated.

  4. Test the recipient map directly. If relay_recipient_maps is configured, verify a lookup works:

    # Test a known-invalid recipient - should return empty
    postmap -q nonexistent@yourdomain.com hash:/etc/postfix/relay_recipients
    
    # Test a known-valid recipient - should return a result
    postmap -q validuser@yourdomain.com hash:/etc/postfix/relay_recipients
    

    If both return empty, the map is not populated. If the map file does not exist, relay_recipient_maps is effectively a no-op.

  5. Check for wildcard entries. Inspect map source files for @domain entries that accept all recipients:

    grep '^@' /etc/postfix/relay_recipients 2>/dev/null
    grep '^@' /etc/postfix/virtual 2>/dev/null
    
  6. Check DNSBL status. Query common blocklists for your IP before the listing propagates further:

    # Replace 1.2.3.4 with your IP in reverse notation
    host 4.3.2.1.bl.spamcop.net
    host 4.3.2.1.zen.spamhaus.org
    host 4.3.2.1.dnsbl.sorbs.net
    

Metrics and signals to monitor

SignalWhy it mattersWarning sign
Bounce rate (status=bounced)Directly measures NDR generation volumeSustained rate above 1% of injection, or sudden 10x increase from baseline
MAILER-DAEMON queue entriesActive bounce messages sitting in queueAny significant count indicates bounces not draining
Deferred queue growth rateBounces to invalid addresses defer on delivery, consuming queue capacityGrowth exceeding 1000 messages/hour with no plateau
Injection vs delivery velocityBounce generation inflates injection without real delivery valueInjection rate far exceeding delivery rate sustained over 5+ minutes
Recipient rejection rateShows whether recipient validation is activeDrop in rejections coinciding with bounce rate spike
Inode usage on queue filesystemEach bounce and double-bounce creates small queue filesAbove 80% used on the partition holding /var/spool/postfix
Relay attempt rejection rateIndicates whether relay restrictions are catching forged trafficDrop in “relay access denied” log entries with rising bounces
Maildrop queue depthBounces are generated locally via pickup daemonPersistent files in maildrop older than 10 minutes

Fixes

Reject unknown recipients at SMTP time

This is the definitive fix. Every recipient must be validated during the SMTP transaction, before the message is queued.

For relay domains, configure relay_recipient_maps with an explicit list of valid recipients:

# The source file must already exist and contain entries.
# Format: validuser@domain  OK
postmap /etc/postfix/relay_recipients
postconf -e 'relay_recipient_maps = hash:/etc/postfix/relay_recipients'
postfix reload

For domains where you cannot maintain a static recipient list (for example, a backup MX for a primary server you do not control), use address verification:

# Review existing restrictions first - postconf -e replaces the entire list.
postconf -h smtpd_recipient_restrictions
postconf -e 'smtpd_recipient_restrictions = reject_unauth_destination, reject_unverified_recipient'
postfix reload

The reject_unverified_recipient check (Postfix 2.1+) probes the destination MTA in real time and caches the result. Be aware of the tradeoff: the official ADDRESS_VERIFICATION_README warns that this can increase load on downstream servers during dictionary attacks or backscatter floods. The persistent verification cache (address_verify_map) mitigates this by caching results across restarts, but is not enabled by default on all distributions.

Do not change unverified_recipient_reject_code from its default of 450 to 250. The Postfix documentation explicitly warns this turns your server into a backscatter source under load.

Remove wildcard catch-all aliases

If your virtual alias map or relay recipient map contains @domain wildcard entries, every address in that domain is accepted. During a spam flood targeting random addresses at your domain, this generates bounces for every forged sender.

Replace wildcard entries with explicit recipient lists. If you must keep a catch-all for operational reasons, understand that your server will generate backscatter during any spam campaign targeting that domain.

Fix local_recipient_maps configuration

The local_recipient_maps parameter specifies which local recipients are valid. By default (Postfix 2.0+), Postfix populates this from the Unix password file and alias database. If it is set to empty, all local recipients are accepted.

The critical gotcha: if you use luser_relay to redirect unknown local recipients, you must set local_recipient_maps to empty (disabling recipient validation). The LOCAL_RECIPIENT_README explicitly warns against doing this on systems receiving mail directly from the internet.

Check your configuration:

postconf -h local_recipient_maps luser_relay

If luser_relay is set and local_recipient_maps is empty on an internet-facing server, you have found the problem.

Stop an active storm

To stop bounce generation immediately, tighten recipient restrictions and reload. New connections will reject invalid recipients at SMTP time. Existing queued bounces still need cleanup.

To remove queued bounce messages without affecting legitimate mail:

# DANGER: This deletes messages from the queue. Verify the pattern matches
# only bounce messages before running.
# mailq output appends * (active) or ! (held) to queue IDs.
# The gsub strips those before passing to postsuper.

# Test the pattern first:
mailq | awk '/MAILER-DAEMON|double-bounce/ {gsub(/[*!]/,"",$1); print $1}' | head -20

# If the output looks correct, delete those queue entries:
mailq | awk '/MAILER-DAEMON|double-bounce/ {gsub(/[*!]/,"",$1); print $1}' | postsuper -d -

Review the output carefully before piping to postsuper. Do not run postsuper -d ALL unless you are prepared to lose every queued message, including legitimate mail.

Address blocklisting

After fixing the root cause, request delisting from any DNSBL that listed your IP. Some blocklists (particularly those targeting backscatter sources) require admin-initiated removal and will re-list you if the underlying problem persists. Fixing recipient validation before requesting delisting is mandatory; delisting without a fix guarantees re-listing.

Prevention

  • Monitor bounce rate explicitly. Bounces count as “sent” in simple delivery metrics. You need a dedicated counter for status=bounced entries, not just delivery success/failure. Alert on sustained rates above 1% or any sudden 10x spike from baseline.
  • Keep relay_recipient_maps current. Stale maps that are missing valid recipients cause false rejections. Maps that include too many entries or wildcards cause backscatter. Sync from your authoritative directory on a schedule.
  • Audit recipient validation after every configuration change. Any change to smtpd_recipient_restrictions, relay_domains, virtual_alias_domains, or transport_maps can silently disable recipient validation. Run postfix check and test with an invalid recipient after changes.
  • Use postscreen to reduce inbound spam volume. Postscreen blocks obvious zombies before they reach smtpd, reducing the volume of spam that reaches your recipient validation logic.
  • Check DNSBL listings proactively. Query major blocklists for your IP on a schedule, not just when recipients complain. Backscatter listings can appear within hours of a storm starting.

How Netdata helps

Netdata’s Postfix collector surfaces the signals that indicate a backscatter storm before it reaches the blocklisting stage:

  • Per-second queue depth tracking across active, deferred, maildrop, and incoming queues. A spike in maildrop combined with deferred growth while MAILER-DAEMON messages accumulate is the earliest indicator of bounce generation.
  • Mail flow velocity correlation. Injection rate outpacing delivery rate, combined with rising bounce counts, distinguishes a backscatter storm from a normal delivery backlog or slow-destination queue buildup.
  • Inode utilization monitoring on the queue filesystem. Each bounce and double-bounce creates small queue files that consume inodes independently of disk space.
  • Process count tracking for smtpd, bounce, cleanup, and pickup daemons. Sustained elevation in bounce daemon activity with high smtpd utilization indicates active NDR generation under load.
  • Anomaly detection on bounce rate and queue growth velocity. Netdata learns the baseline for each signal and flags deviations without manually tuned thresholds.