2026年11月14日

2026年11月14日

Postfix Queue Management: postqueue, postcat and postsuper Explained

This article is a localized edition of the Japanese original. Read the Japanese original

When Postfix cannot deliver a message right away, it puts it in a queue and retries later. When mail does not arrive, sending is delayed, or a server is sending a flood of mail, checking the queue first usually points you toward the cause.

This article covers the three commands used to check and manage the queue.

Command Main use Run as
postqueue Listing the queue, requesting delivery Listing works as a regular user
postcat Showing the contents of one queued message root
postsuper Delete, hold, release, requeue root

The commands and output were checked with Postfix 3.10 on Debian 13 as of October 2026.

Queue types

The Postfix queues are directories under /var/spool/postfix/. Do not delete or move the files directly; use the commands in this article.

Queue Contains
maildrop Mail just submitted with the local sendmail command
incoming Mail that was accepted and is being prepared for delivery
active Mail currently being delivered
deferred Mail that could not be delivered because of a temporary error and is waiting to be retried
hold Mail put on hold by an administrator. Not delivered until released
corrupt Damaged, unreadable queue files

When people say "mail is piling up in the queue", they almost always mean deferred mail.

List the queue

postqueue -p

mailq gives the same result. The output looks like this.

-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
949F63B5C1      285 Thu Oct 29 17:36:33  sender@mail.example.test
                    (connect to 127.0.0.1[127.0.0.1]:2525: Connection refused)
                                         alice@example.net

9AF003B5C2      285 Thu Oct 29 17:36:33  sender@mail.example.test
                    (connect to 127.0.0.1[127.0.0.1]:2525: Connection refused)
                                         bob@example.net

-- 0 Kbytes in 2 Requests.
  • First line: queue ID, size (bytes), arrival time, sender
  • The line in ( ): why delivery failed (the delay reason). This is the most useful part when looking for the cause
  • Last line: recipient

A symbol may follow the queue ID directly.

Symbol Meaning
* In the active queue, being delivered
! In the hold queue, on hold
# Forced to expire with postsuper -e or similar (returned to the sender at the next delivery attempt)
none Waiting for a retry in deferred or similar

The final line, such as -- 0 Kbytes in 2 Requests., shows the number of messages. When the queue is empty, it shows Mail queue is empty.

List the queue as JSON

postqueue -j prints one line of JSON per message. This is easier to handle in scripts.

postqueue -j
{"queue_name": "deferred", "queue_id": "949F63B5C1", "arrival_time": 1793295393, "message_size": 285, "forced_expire": false, "sender": "sender@mail.example.test", "recipients": [{"address": "alice@example.net", "delay_reason": "connect to 127.0.0.1[127.0.0.1]:2525: Connection refused"}]}

With jq you can count messages per queue or per delay reason.

# Count per queue
postqueue -j | jq -r .queue_name | sort | uniq -c

# Count per delay reason (most frequent first)
postqueue -j | jq -r '.recipients[].delay_reason' | sort | uniq -c | sort -rn | head

Count by recipient domain

qshape tallies queued mail by recipient domain and by age. Use it to see whether only mail to a particular domain is piling up.

sudo qshape deferred
                                         T  5 10 20 40 80 160 320 640 1280 1280+
                                  TOTAL  3  3  0  0  0  0   0   0   0    0     0
                            example.net  2  2  0  0  0  0   0   0   0    0     0
                            example.org  1  1  0  0  0  0   0   0   0    0     0

T is the total, and the numbers to the right are counts by age (minutes). On Debian / Ubuntu, qshape is included in the postfix package.

View one message

sudo postcat -q 949F63B5C1

This shows the envelope (sender and recipients), headers and body together. To see only part of it, put one of these options before -q.

Command Shows
sudo postcat -hq QUEUE_ID Headers only
sudo postcat -bq QUEUE_ID Body only
sudo postcat -eq QUEUE_ID Envelope only

When checking whether the server is being abused to send spam, look at the Received: and From: headers. Mail submitted by a program on the server with the sendmail command records the submitting user's ID, as in Received: by mail.example.test (Postfix, from userid 0). If it is the web server's user (www-data on Debian / Ubuntu is usually 33), you can guess the mail came from PHP, such as WordPress.

Message contents include personal information. Look only at what you need for the investigation.

Operate on the queue

Retry now

# Attempt delivery of all queued mail now
sudo postqueue -f

# Attempt delivery of one message now
sudo postqueue -i 949F63B5C1

deferred mail is normally retried automatically after a while. Use these when you have fixed the cause (DNS, a remote server outage, a firewall and so on) and do not want to wait. Repeating postqueue -f while a lot of undeliverable mail is queued slows down delivery of other mail too, so fix the cause first.

Hold and release

# Put on hold (move to the hold queue)
sudo postsuper -h 949F63B5C1

# Release from hold
sudo postsuper -H 949F63B5C1

Held mail is neither delivered nor expired until you release or delete it. This is useful when you want to stop suspected spam before deciding whether to delete it.

Delete

# Delete one message
sudo postsuper -d 949F63B5C1

# Delete all mail in the deferred queue
sudo postsuper -d ALL deferred

# Delete all queued mail
sudo postsuper -d ALL

Deleted mail cannot be recovered, and no error message is returned to the sender. Before using ALL, check with postqueue -p what will be deleted.

Delete in bulk by recipient or sender

postsuper -d - reads queue IDs from standard input and deletes them. Filter the targets with postqueue -j and jq and pipe them in to delete only mail for a specific recipient or sender.

# Delete mail addressed to bob@example.net
postqueue -j \
  | jq -r 'select(any(.recipients[]; .address == "bob@example.net")) | .queue_id' \
  | sudo postsuper -d -

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

To be safe, run it first without | sudo postsuper -d -, confirm that the printed queue IDs are the ones you intend, then delete.

Expire and return to the sender

sudo postsuper -e 949F63B5C1

-e marks a message as expired. At the next delivery attempt (which you can trigger with postqueue -i and the like), Postfix gives up and returns an error message to the sender. Unlike deletion, the sender learns that the mail was not delivered.

Requeue

sudo postsuper -r 949F63B5C1
sudo postsuper -r ALL

-r puts mail back into the queue so that address rewriting and next-hop decisions are redone. Use it after changing settings such as relayhost or transport_maps when you want queued mail to use the new settings.

Retry intervals and lifetime

How often deferred mail is retried and when Postfix gives up are set by the following parameters (values are Postfix 3.10 defaults).

Parameter Default Meaning
queue_run_delay 300s How often the deferred queue is scanned
minimal_backoff_time 300s Shortest wait before a retry
maximal_backoff_time 4000s Longest wait before a retry
maximal_queue_lifetime 5d Mail still undeliverable after this period is returned to the sender
bounce_queue_lifetime 5d How long error messages (bounces) themselves stay in the queue

Check the current values with postconf.

postconf maximal_queue_lifetime bounce_queue_lifetime queue_run_delay minimal_backoff_time maximal_backoff_time

Check regularly that the queue is not piling up

A simple script that logs a message when the queue exceeds a set number of messages. Save it as /usr/local/bin/postfix-queue-check.sh.

#!/bin/bash
# If the Postfix queue holds more than LIMIT messages, log it and exit with code 1
LIMIT=50

COUNT=$(/usr/sbin/postqueue -j | wc -l)
if [ "$COUNT" -gt "$LIMIT" ]; then
  /usr/bin/logger -t postfix-queue-check "queue has $COUNT messages (limit $LIMIT)"
  exit 1
fi
sudo chmod 755 /usr/local/bin/postfix-queue-check.sh

Register it with sudo crontab -e to run every 10 minutes.

*/10 * * * * /usr/local/bin/postfix-queue-check.sh

You can read the entries with journalctl -t postfix-queue-check. Since mail sending itself may be what has stopped, use something other than email (a chat webhook or an external monitoring service) if you need notifications.

Common delay reasons

Example reason in postqueue -p Likely cause
connect to ...:25: Connection timed out Outbound connections to port 25 are blocked (OP25B at the cloud or ISP), or the remote server does not respond
connect to ...: Connection refused The remote server or relay is not listening on that port
Host or domain name not found The MX / A record for the recipient domain cannot be looked up (misspelled domain, DNS failure)
451 4.7.1 ... try again later and similar The remote server is temporarily refusing (greylisting, rate limits)

After fixing the cause, retry with sudo postqueue -f and confirm with postqueue -p that the count goes down. You can follow delivery progress by searching the mail log for the queue ID (/var/log/mail.log on Debian / Ubuntu, /var/log/maillog on the RHEL family, journalctl where rsyslog is not installed).

Summary

  • Use postqueue -p (mailq) to see the list and delay reasons. In scripts, use postqueue -j with jq
  • Use qshape deferred to see which domains mail is piling up for
  • Use postcat -q to view one message (-h headers, -b body)
  • Use postsuper to delete (-d), hold (-h / -H), expire (-e) and requeue (-r). -d - deletes only the filtered messages in bulk
  • Fix the cause before retrying with postqueue -f

Related articles:

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲