I have a server with multiple domains. How can I clear all Postfix queue messages for a specific domain?
7 Answers
UPDATE 2021-04-18:
mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" } { if ($8 ~ /@example\.com/ && $9 == "") print $1 }' | tr -d '*!' | postsuper -d -
Whereas $7
=sender, $8
=recipient1, $9
=recipient2. You can also adapt the rule for other recipients ($9
) to your needs.
The command is based on an example of the postsuper manpage which an example command matching a full recipient mail address:
mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" } { if ($8 == "[email protected]" && $9 == "") print $1 }' | tr -d '*!' | postsuper -d -
Old content:
This command deletes all mails sent from or to addresses that end with @example.com
:
sudo mailq | tail -n +2 | awk 'BEGIN { RS = "" } /@example\.com$/ { print $1 }' | tr -d '*!' | sudo postsuper -d -
-
2
-
The
tr -d
can be refactored into the Awk script, too. Replace{ print $1 }
with{ r = $1; gsub(/[!*]/, "", r); print r }
– tripleeeCommented Oct 26, 2018 at 10:07 -
If you copy, edit and paste the example from postsuper
man
page, you'll avoid unwanted side effects.– symcbeanCommented Mar 26, 2021 at 16:14 -
Grep solution
mailq | grep example.com -B1 | grep -oE "^[A-Z0-9]{10,20}" | sudo postsuper -d -
assumes ID is between 10 and 20 digits, (based on inodes)
-
1Not sure why is such an assumption, my IDs are of length 13. Probably you should just replace to
{10,20}
or so. Otherwise the best easy answer! Commented Jul 8 at 14:27
I have tried this solution in ubuntu 12.04, and it doesn't work this way:
sudo mailq | tail +2 | awk 'BEGIN { RS = "" } / @example\.com$/ { print $1 }' | tr -d '*!' | sudo postsuper -d -
I need to change to this way:
postqueue -p | tail -n +2 | awk 'BEGIN { RS = "" } /@example\.com/ { print $1 }' | tr -d '*!' | postsuper -d -
I want to give a "more modern" answer parsing the json
output of postqueue -j
. It depends on the package jq
to filter the output and is much more understandable (and debuggable):
postqueue -j | jq -rc 'select(.recipients[].address | match(".*@example\\.com$"))["queue_id"]' | postsuper -d -
# For an exact Mail match
postqueue -j | jq -rc 'select(.recipients[].address == "[email protected]")["queue_id"]' | postsuper -d -
Another less related argument for this solution besides readability is it's easy adaptability:
# Filter on delay_reason being "Connection timed out"
postqueue -j | jq -rc 'select(.recipients[].delay_reason | match(".*Connection timed out$"))["queue_id"]' | postsuper -d -
# Filter on arrival_time being older than certain age
postqueue -j | jq -rc 'select(.arriveal_time < 1710265065)["queue_id"]' | postsuper -d -
# Filter on the size of messages
postqueue -j | jq -rc 'select(.message_size > 100000)["queue_id"]' | postsuper -d -
This is the full json, showing all filterable values:
{
"queue_name": "deferred",
"queue_id": "4TwLyJ4Gpyz2xVB",
"arrival_time": 1710407000,
"message_size": 15932,
"forced_expire": false,
"sender": "MAILER-DAEMON",
"recipients": [
{
"address": "[email protected]",
"delay_reason": "delivery temporarily suspended: connect to mail.example.com[111.222.333.444]:25: Connection timed out"
}
]
}
Look at pfdel.pl, a mandatory tool to manage the queue. It takes a regexp and remove the mails waiting in queue corresponding to your domain.
When you want to delete messages from or to e-mail addresses at a specific domain, this command works for me:
mailq | \
tail -n +2 | \
awk 'BEGIN { RS = "" } / @example\.com$/ { print $1 }' | \
tr -d '*!' | \
postsuper -d -
Also works for deleting e-mails from or to specific e-mail addresses by supplying for example mail@example\.com$/
instead of @example\.com$/
.
Taken from a comment on howtoforge.com. See there for related solutions and the command in one line. (I used bash line continuation for readability).
A very similar command that allows to make deletion dependent on whether the address appears as sender, recipient etc. is found in man postsuper
, where it says about -d
:
For example, to delete all mail with exactly one recipient [email protected]:
mailq | \ tail -n +2 | \ grep -v '^ *(' | \ awk 'BEGIN { RS = "" } { if ($8 == "[email protected]" && $9 == "") print $1 }' | \ tr -d '*!' | \ postsuper -d -
(The variables mean: $7=sender, $8=recipient1, $9=recipient2. I changed the quote to use tail -n +2
, since their tail +2
does not work any more, at least on some modern systems.)
-
-
1The backslashes at the end of line are not actually necessary; the shell understands that the command continues on the next line if the last token is
|
(or||
or&&
or a bunch of others).– tripleeeCommented Oct 26, 2018 at 10:10
I've modified it little bit:
mailq | grep -B1 | grep -oE "^[A-Z0-9]{12}" | xargs -I% postsuper -d %
-
4
-
Running hundreds of instances of
postsuper
is not an improvement at all.xargs
is nice when you use it properly, but this is not one of those situations.– tripleeeCommented Oct 26, 2018 at 10:11