Short answer: Count the queue with exim -bpc, see who it belongs to with exim -bp | exiqsumm, and read why one message is stuck with exim -Mvl <id>. Retry everything with exim -qff only after you know the queue is legitimate. Remove frozen or spam mail by piping exiqgrep -i (filter by -z, -f sender or -r recipient) into exim -Mrm. If the queue keeps refilling, find the script or mailbox behind it before you flush anything.
Applies to cPanel & WHM 11.138, Exim 4.100.1, AlmaLinux 9.8
We ran the read-only commands on this page (exim -bpc, exim -bp, exiqsumm, exiqgrep, exiwhat, exim -Mvh/-Mvl, exigrep) on our lab server (AlmaLinux 9.8, cPanel & WHM 11.138, Exim 4.100.1) on 6 October 2026. The commands that deliver, thaw or delete mail were checked against the Exim specification (linked below) but not run on the lab, because they change the queue.
Table of Contents
Check how big the queue is and who owns it
Start with numbers, not with a flush. These commands only read the spool in /var/spool/exim:
exim -bpc # total messages in the queue
exim -bp | exiqsumm # summary per recipient domain
exiqgrep -c # count (accepts the same filters as below)
exiqgrep -z -c # how many are frozen
On our lab the queue held four messages, all frozen. This is the real output, with addresses and the hostname masked:
# exim -bpc
4
# exim -bp | head
8h 2.0K 1xDpOc-00000000F4S-3Blx <> *** frozen ***
[masked]
8h 2.1K 1xDpOd-00000000F4h-0p4c <> *** frozen ***
[masked]
# exim -bp | exiqsumm
Count Volume Oldest Newest Domain
----- ------ ------ ------ ------
4 8396 8h 8h [server hostname]
---------------------------------------------------------------
4 8396 8h 8h TOTAL
How to read exim -bp: age, size, message ID, sender in angle brackets, then the recipients. A sender of <> means the message is a bounce (a delivery status notification). Hundreds of <> messages to many outside domains usually means someone sent spam from the server and the bounces are coming back.
If the queue is very large, exim -bp can take a long time because it sorts by arrival time. exim -bpr skips the sorting, and exim -bpc just counts.
Find out why a message is stuck
Take one message ID from the list and look at its headers and its message log:
exim -Mvh 1xDpOc-00000000F4S-3Blx # header spool file (-H)
exim -Mvl 1xDpOc-00000000F4S-3Blx # message log: every delivery attempt
exim -Mvb 1xDpOc-00000000F4S-3Blx # body (-D), useful to spot spam content
exigrep 1xDpOc-00000000F4S-3Blx /var/log/exim_mainlog
On the lab, the message log explained the freeze in one line:
2026-10-05 15:34:50 Received from <> R=1xDpOc-00000000F4L-2EX0 U=mailnull P=local S=2043 T="Mail delivery failed: returning message to sender"
2026-10-05 15:34:50 [masked] R=localuser_root : root cannot accept local mail deliveries
*** Frozen (delivery error message)
This is a common pattern on cPanel. Something on the server mailed root@ the hostname, the delivery failed, and the bounce was addressed back to root. cPanel’s localuser_root router in /etc/exim.conf refuses local delivery to root with :fail: root cannot accept local mail deliveries. Exim cannot bounce a bounce, so it freezes it. The R= value is the ID of the original message: grep the main log for it to see what sent it, fix that, and then remove the frozen bounces.
Other reasons you will see in -Mvl or /var/log/exim_mainlog:
- Remote temporary errors (4xx, greylisting, “try again later”): the message stays queued and Exim retries on its schedule. These are not frozen.
- Rejections for your IP (blocklist or rate limiting at Gmail, Microsoft and others): see our IP blacklisted runbook.
- Frozen (delivery error message): a bounce that could not be delivered. These are usually safe to remove.
- Messages held by sending limits, for example a domain that hit its hourly limit: covered in Exim outbound mail limits in WHM.
Flush the queue: force delivery safely
Do not force a queue run while you still suspect spam. A forced run sends every queued spam message out at once and makes a blocklisting much more likely. Check the sender list first (next sections) and remove spam before you flush.
Once the queue is legitimate (for example after a network or DNS outage), use one of these:
exim -qf # force a delivery attempt for every NON-frozen message
exim -qff # same, but frozen messages are included
exim -M 1xDpOc-00000000F4S-3Blx # one message (frozen messages are thawed first)
exim -Rff example.com # every message with a recipient at example.com, frozen ones too
According to the Exim specification, one f forces delivery for every non-frozen message regardless of retry times, while ff includes frozen messages too. -M ignores retry hints and thaws frozen messages before trying. Messages that are being delivered at that moment are left alone.
In WHM, the same actions live in Mail Queue Manager (search WHM for “Mail Queue”): search by sender, recipient or date, then use Deliver Selected, Deliver All, Delete Selected or Delete All. Frozen messages show an unfreeze icon, and the WHM documentation notes it unfreezes one message at a time. For more than a handful of messages, the command line is faster.
Thaw or remove frozen messages
Thawing tells Exim to try a frozen message again on the next queue run. Do this only when you fixed the reason it froze:
exim -Mt 1xDpOc-00000000F4S-3Blx # thaw one message
exiqgrep -z -i | xargs -r exim -Mt # thaw all frozen messages
Most frozen messages on a cPanel server are undeliverable bounces. Removing them is the usual fix. Save the list first so you can explain later what was deleted:
exiqgrep -z -c # 1. how many
exiqgrep -z > /root/frozen-$(date +%F).txt # 2. keep a record (long format)
exiqgrep -z -i | xargs -r exim -Mrm # 3. remove them
exiqgrep -z -c # 4. should now report 0 matches
exim -Mrm removes a message without sending any bounce. If you want the sender to be told, use exim -Mg <id> (“give up”) instead: for normal messages Exim sends a delivery failure notice to the sender, and bounces are simply discarded.
Never delete files under /var/spool/exim/input by hand. Each message has a -H and a -D file, and Exim also keeps hints databases. Removing files directly can leave half-messages and lock errors. Use exim -Mrm, which also skips messages that are being delivered at that moment.
Bulk-delete mail by sender, recipient, domain or age
exiqgrep selects messages and prints their IDs with -i. The patterns are regular expressions. Always run the same filter with -c (count) or without -i (long list) before you pipe it into exim -Mrm.
| Goal | Check first | Then delete |
|---|---|---|
| All mail from one sender | exiqgrep -c -f 'bob@example.com' | exiqgrep -i -f 'bob@example.com' | xargs -r exim -Mrm |
| All mail from one domain | exiqgrep -c -f '@example\.com>' | exiqgrep -i -f '@example\.com>' | xargs -r exim -Mrm |
| All bounces (sender <>) | exiqgrep -c -f '^<>$' | exiqgrep -i -f '^<>$' | xargs -r exim -Mrm |
| Mail to one recipient domain | exiqgrep -c -r '@gmail\.com$' | exiqgrep -i -r '@gmail\.com$' | xargs -r exim -Mrm |
| Older than 2 days | exiqgrep -c -o 172800 | exiqgrep -i -o 172800 | xargs -r exim -Mrm |
Notes from the exiqgrep -h help on our lab: -f matches the sender field, which is wrapped in angle brackets, so '^<>$' matches only the empty bounce sender. -o and -y take seconds (older than / younger than). -z limits the match to frozen messages and -x to non-frozen ones, and both combine with the other filters. For example, exiqgrep -z -f '^<>$' -i lists only frozen bounces.
With tens of thousands of IDs, xargs splits the list into batches automatically. The -r flag stops it from running exim -Mrm with no arguments when nothing matched.
Find the script or mailbox that filled the queue
Deleting spam without finding the source only buys you an hour. Look for the source from three angles:
- Which local user and directory? Mail sent by PHP or cron is logged with a
cwd=(working directory) entry in/var/log/exim_mainlog. Count them:grep -o 'cwd=/home[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head. A busycwd=/home/bob/public_html/wp-content/uploads/...is a strong hint of an uploaded mailer script. - Which mailbox login? SMTP-authenticated mail is logged with the authenticator name. On cPanel these are
dovecot_loginanddovecot_plain(we confirmed this withexim -bP authenticator_list). Count logins:grep -o 'A=dovecot_[a-z]*:[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head. One mailbox sending thousands of messages usually has a stolen password. - Which PHP file? When PHP’s
mail.add_x_headeris On (it was On for ea-php83 on our lab), PHP adds anX-PHP-Originating-Scriptheader that names the UID and script. Read it withexim -Mvh <id>on a few spam messages.
exiwhat shows what each running Exim process is doing right now. On a quiet server it shows just the daemon; during a spam run it shows deliveries in progress. The Exim manual warns that it signals every Exim process, so run it when you need it, not from a tight loop. Our lab output:
# exiwhat
17170 daemon(4.100.1): [0+0] -q15m, listening for SMTP on port 25 (IPv6 and IPv4) port 587 (IPv6 and IPv4) and for SMTPS on port 465 (IPv6 and IPv4)
Once you know the source: change the mailbox password, remove the script, and set per-domain limits. The full process is in find the source of outgoing spam on cPanel. Our Exim Mail Queue Report script gives the per-sender and per-domain view in one run.
Check that it worked
exim -bpc # should be falling, or 0
exiqgrep -z -c # frozen count
exim -bp | exiqsumm | tail -3 # what is left, by domain
tail -f /var/log/exim_mainlog # watch new deliveries: "=>" delivered, "**" failed, "==" deferred
Check again after 30 minutes and again the next day. A queue that grows back to the same size means the source is still active.
Common problems
- The queue refills within minutes. The compromised script or mailbox is still sending. Find it as shown above. As a stopgap, suspend outgoing email for that cPanel account (the WHM API 1 function is
suspend_outgoing_email, for examplewhmapi1 suspend_outgoing_email user=bob), and lift the suspension after cleanup. - “Message is frozen” repeats every 15 minutes in the log. That is the queue runner (the daemon on our lab runs with
-q15m) skipping the frozen message. It is harmless but noisy. Remove or thaw the message. exim -Mrmsays nothing happened for some IDs. Messages that are being delivered at that moment are not changed. Run the same command again a minute later.- Legitimate mail stuck as “deferred” to one provider. Do not keep forcing it with
-qff. Read the 4xx/5xx text in-Mvl. It usually points to reputation, PTR, SPF or DKIM, which a flush does not fix. - A huge queue makes WHM Mail Queue Manager time out. Use
exiqgrepandexim -Mrmon the command line instead.
Official documentation: Exim specification: the Exim command line · Exim specification: Exim utilities (exiqgrep, exiwhat, exiqsumm) · cPanel docs: Mail Queue Manager
Related: Outgoing Spam cPanel: Find the Source and Stop It · Exim Outbound Mail Limits WHM: Stop Spam Runs Fast · Exim Mail Queue Report · Mail server IP blacklisted: delisting runbook · Exim 4.100 Security Fixes: Critical 2026 Changes for Hosting
See also: SMTP Bounce Explainer: What Your Bounce Message Means · Spamhaus 550 5.7.1 Blocked: Fix SBL, XBL, CSS, PBL and DBL
See also: Exim Log Cheat Sheet: exigrep, exiqgrep, eximstats and Log Flags · Exim “Retry Time Not Reached for Any Host”: Causes and Fix
Frequently asked questions
How do I flush the Exim queue on cPanel?
Run exim -qf to force a delivery attempt for all non-frozen messages, or exim -qff to include frozen ones. Check the queue for spam first, because a forced run sends everything that is queued.
How do I delete all frozen messages in Exim?
Count them with exiqgrep -z -c, save the list with exiqgrep -z, then run exiqgrep -z -i | xargs -r exim -Mrm. Check again with exiqgrep -z -c.
What is the difference between exim -Mrm and exim -Mg?
exim -Mrm removes the message silently. exim -Mg gives up on delivery: for normal messages the sender gets a failure notice, and bounce messages are discarded.
Why are messages frozen with “root cannot accept local mail deliveries”?
cPanel’s Exim configuration refuses local delivery to root. A bounce addressed to root then cannot be delivered or bounced again, so Exim freezes it. Find the original message from the R= ID in the message log, fix what sent it, and remove the frozen bounces.
Is it safe to delete files in /var/spool/exim/input?
No. Use exim -Mrm instead. It removes both spool files and leaves alone any message that is being delivered at that moment.
Maintenance record
This guide changes servers, data or security settings, so we re-check it against current versions on a fixed schedule. Take a backup or snapshot before you start.
- Maintained by
- srvScripts editorial team
- Supported versions
- Tested on cPanel & WHM 11.138, Exim 4.100.1, AlmaLinux 9.8
- Last full review
- Next review