Remove stuck emails from postfix mail queue

Sometimes mails queue up in the postfix mail queue for some reason, maybe the destination mailserver does not exist or some emails have a recipient address that is incorrect. This is generally not a problem, but sometimes, a system automation may be generating such emails and sends them in huge amounts. Mail gateways to which the emails would be delivered could then be throttling the connections involved, making mails back up even more. In such cases, it makes sense to remove these emails from the queue so that other emails can get delivered without any further delay.

When postfix accepts an email, it is placed in a queue for further processing. Then from that queue, another postfix daemon picks it up and tries to deliver it. If delivery fails (temporarily) the email remains in the queue. Such emails will be tried over and over again until a point is reached when the email is considered not deliverable.

When postfix receives a huge number of emails, they are also added to the queue (assuming the postfix server is not throttling). When postfix then tries to deliver those emails to the next mail server, it might hit a limit there. Especially in a setup where all emails are forwarded to another mail server, this huge amount of generated emails could delay the delivery of other emails by hours, days, or longer! If a huge number of emails is clogging the mail queue, it makes sense to remove them manually from the queue.

If there are only one or two emails which should be removed, you can just use their Queue ID from the mailq(1) output and delete them with the following command.

$ postsuper -d CB7E5B0067
postsuper: CB7E5B0067: removed
postsuper: Deleted: 1 messages

The postsuper(1) command will delete the message with the queue ID “CB7E5B0067” from the queue. With a very few messages, this can be a handy and quick way to remove them. In the case where an automated system has generated hundreds or thousands of emails, a more automated approach is required.

Sorting through the mail queue

It’s not quite as easy as using grep to sort out the queued messages from the mailq output, as the output delivered by mailq(1) is multi line. It might be possible to simply grep(1), as long as the details are on the same line as the queue-id. When the details are in the second row, a little bit more work is necessary.

A typical mailq output will look similar to this.

-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
E2AE38F3712     4883 Mon Nov 27 20:45:11  user@example.com
(delivery temporarily suspended: lost connection with mx3.qq.com[123.123.123.123] while sending MAIL FROM)
                                         1506487969@qq.com

E584DB45F5     4337 Mon Nov 27 17:01:48  user@example.com
(delivery temporarily suspended: lost connection with mx3.qq.com[123.123.123.123] while sending MAIL FROM)
                                         631676778@qq.com

-- 638 Kbytes in 2 Requests.

The following command, described in detail below, will format the mailq output, filter the list for the string “user@example.com” and delete the associated messages from the queue.

$ mailq | grep -v '^\-' | awk '/^$/{print ""}{printf $0" "}' | grep 'user@example\.com' | awk '{gsub(/!|\*/, "", $1); print $1}' | postsuper -d -

Remove unnecessary lines

First of all, the mailq(1) command is invoked. The output is then piped into a grep(1) to remove lines starting with a hyphen “-” (lines starting with a hyphen are the header line at the beginning and the statistic line at the end of the output).

Wrap into one line per message

The output without the header and statistic line is then piped into awk(1). The first part of the awk command simply prints a newline for each empty line found in the input, while the second part prints the complete input line followed by a space but without any newline. As the output of mailq(1) contains one empty line between the messages, the result is one line of information per queued message.

Filter out messages

With the second grep(1) command, The list can be filtered for the messages to be deleted. With all the details available from the mailq(1) in one line with the queue-id, a simple pattern can be used at this point to identify the messages to be deleted.

Extract the queue-id’s

After the message has been filtered, The list has to be reduced to contain only the queue-id so that it can be fed into the postsuper(1) command. The last awk(1) is used to extract the queue-id, as well as removing “*” or “!” in front of the queue-id. These symbols are used to mark the queue status of the message in the output, and are not part of the queue-id, so must be removed, This removal is done using the “gsub” function of the awk command.

Delete the queued message

Finally we have the postsuper(1) command with the “-d” option to delete a message. The last option hyphen “-” is used to instruct postsuper(1) to read the queue-id from the input pipe.

Test before you delete

I always suggest to test the pattern used to identify the messages to be deleted. Simply run this part of the command to see which emails match the pattern defined. If necessary, adjust the pattern to avoid deleting messages which are not meant to be deleted.

$ mailq | grep -v '^\-' | awk '/^$/{print ""}{printf $0" "}' | grep 'user@example\.com'

After the pattern defined in the last grep matches only the expected messages, add the last two commands (awk and postsuper) to actually delete the queued messages.


Read more of my posts on my blog at https://blog.tinned-software.net/.

This entry was posted in Mailserver. Bookmark the permalink.