Server IP blacklisted or sending spam: stop it and get delisted

Updated November 2026

If your mail is bouncing with “blocked” errors or your host has sent an abuse notice, your server is probably sending spam. Stop the outgoing flood first, find out how it gets in, close that hole, and only then ask to be delisted. If you ask before the problem is fixed, the IP will be listed again, often for longer.

Do this first.

  1. Stop outgoing delivery while you investigate: sudo postconf -e 'defer_transports = smtp' then sudo postfix reload. Mail still queues, but nothing leaves.
  2. Look at the queue and the logs to find the sender (account, script or relay).
  3. Block that source (change the password, disable the script) before you delete anything.
  4. Do not request delisting yet.

Symptoms

Step 1: look at the queue

These commands are for Postfix. mailq is the same as postqueue -p.

# How many messages, and the last summary line
mailq | tail -n 1

# Top senders in the queue (needs jq: apt install jq / dnf install jq)
postqueue -j | jq -r '.sender' | sort | uniq -c | sort -rn | head

# Read one message: envelope and headers
sudo postcat -q QUEUE_ID | less

Look at the sender address, the Received: headers and, for PHP scripts, an X-PHP-Originating-Script header. Then decide which of the three common sources you have.

Step 2: find the source

A compromised mail account

Spammers log in with a stolen password and send through your server on port 587 or 465. Postfix logs the login name as sasl_username. Mail logs are in /var/log/mail.log on Debian/Ubuntu, /var/log/maillog on the RHEL family, or in the journal if no syslog daemon is installed.

# Which accounts sent the most today
sudo grep -h -o 'sasl_username=[^ ,]*' /var/log/mail.log | sort | uniq -c | sort -rn | head
# Journal instead of log file
sudo journalctl --since today | grep -o 'sasl_username=[^ ,]*' | sort | uniq -c | sort -rn | head

One account with hundreds of logins from many countries is the culprit. Change its password, end its sessions, and check whether the password was reused elsewhere. See Leaked credentials.

A script on a website

A hacked or badly written PHP form sends mail through the local sendmail command. Postfix logs these as postfix/pickup lines with the Unix user ID that submitted them:

sudo grep 'postfix/pickup' /var/log/mail.log | grep -o 'uid=[0-9]*' | sort | uniq -c | sort -rn
getent passwd 33      # which user is uid 33 (www-data on Debian/Ubuntu)

# PHP files changed in the last 7 days under the web root
sudo find /var/www -name '*.php' -mtime -7 -ls

To see which script sends mail, set mail.add_x_header = On (adds X-PHP-Originating-Script with the user ID and file name) and mail.log = /var/log/php-mail.log (logs every mail() call with the script path and line) in php.ini, then restart PHP-FPM. Treat an unknown script as a break-in: see Website hacked.

An open relay

An open relay accepts mail from anyone to anywhere. Since Postfix 2.10 the default smtpd_relay_restrictions only lets trusted networks (mynetworks) and logged-in users relay. Check that nobody widened it:

postconf mynetworks mynetworks_style smtpd_relay_restrictions smtpd_recipient_restrictions

mynetworks should list only your own addresses, such as 127.0.0.0/8 [::1]/128, never a whole provider range or 0.0.0.0/0. One of the two restriction lists must contain reject_unauth_destination or defer_unauth_destination. Test from a machine outside your network (swaks is packaged for Debian/Ubuntu and in EPEL):

swaks --server mail.example.com --from test@example.net --to someone@example.org

The server should refuse with “Relay access denied”. If it accepts the message, you have an open relay.

Step 3: stop it and clean the queue

Once the source is blocked, remove the spam. postsuper needs root, and ALL must be in capitals.

# Put everything on hold, then release the good mail later
sudo postsuper -h ALL

# Delete all queued mail from one spam sender
postqueue -j | jq -r 'select(.sender == "spam@example.com") | .queue_id' | sudo postsuper -d -

# Release the remaining legitimate mail
sudo postsuper -H ALL

Use sudo postsuper -d ALL only if nothing in the queue is worth keeping. Then remove the delivery block and reload:

sudo postconf -e 'defer_transports ='
sudo postfix reload

Watch the log for ten minutes. If the queue grows again, the hole is still open.

Stop delivery Find source Block it Clean queue Fix, harden Ask to delist
Delisting comes last. Asking earlier usually leads to a new listing.

Step 4: fix the basics

Receivers judge a mail server on a few DNS records. Google’s sender rules, for example, require SPF or DKIM for every sender, valid forward and reverse DNS for the sending IP, and TLS; bulk senders (over 5,000 messages a day to Gmail) also need DMARC.

Reverse DNS (PTR)
The IP must resolve to a host name, and that name must resolve back to the IP. You set the PTR record at your hosting provider, not in your own zone. Check with dig +short -x 203.0.113.10 and dig +short A mail.example.com.
SPF
A TXT record listing which servers may send for the domain, for example example.com. TXT "v=spf1 ip4:203.0.113.10 -all".
DKIM
Signs each message with a key whose public half is published in DNS. On Postfix this is usually done with OpenDKIM or rspamd.
DMARC
Tells receivers what to do when SPF and DKIM checks fail and where to send reports. Start with _dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com" and move to quarantine or reject once reports look clean. DMARC is now specified in RFC 9989 (May 2026), which replaced RFC 7489.

Step 5: request delisting

Note the date and reference number of each request, and keep the log evidence of your fix.

Confirm it is fixed

When to get help

Contact your hosting provider if it blocked port 25 or if the listing is an SBL (only the IP owner can request removal). If you found unknown scripts or accounts, assume a wider compromise and follow Abuse complaint and the incident steps in Incident response.

Sources