Postfix Flush the Mail Queue

Posted on in Categories Howto, Linux, Mail server, Postfix last updated October 25, 2007

Traditionally you use the “sendmail -q” command to flush mail queue under Sendmail MTA. Under Postfix MTA, just enter the following command to flush the mail queue:
# postfix flush
OR
# postfix -f

To see mail queue, enter:
# mailq

To remove all mail from the queue, enter:
# postsuper -d ALL

To remove all mails in the deferred queue, enter:
# postsuper -d ALL deferred

postfix-delete.pl script

Following script deletes all mail from the mailq which matches the regular expression specified as the first argument (Credit: ??? – I found it on old good newsgroup)

#!/usr/bin/perl
 
$REGEXP = shift || die "no email-adress given (regexp-style, e.g. bl.*\@yahoo.com)!";
 
@data = qx</usr/sbin/postqueue -p>;
for (@data) {
  if (/^(\w+)(\*|\!)?\s/) {
     $queue_id = $1;
  }
  if($queue_id) {
    if (/$REGEXP/i) {
      $Q{$queue_id} = 1;
      $queue_id = "";
    }
  }
}
 
#open(POSTSUPER,"|cat") || die "couldn't open postsuper" ;
open(POSTSUPER,"|postsuper -d -") || die "couldn't open postsuper" ;
 
foreach (keys %Q) {
  print POSTSUPER "$_\n";
};
close(POSTSUPER);

For example, delete all queued messages from or to the domain called fackspamdomain.com, enter:
./postfix-delete.pl fackspamdomain.com
Delete all queued messages that contain the word “xyz” in the e-mail address:
./postfix-delete.pl xyz

Updated for accuracy.

Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on Twitter, Facebook, Google+.

61 comment

  1. The command for “To remove all bounced mail from Queue, enter:” is incorrect. That command will completely delete all the contents of your Mail Queue.

    When I read this I thought it would eliminate only the bounced back emails that were sitting in my queue. I was wrong. It deleted all 6,000 of the emails sitting in my queue.

    If this post is any sign of the type of information provided on this website, the readers are in for a big surprise…and some pink slips from their employer..

  2. I’ve found this code on two different blogs and have received compilation errors both times similar to:

    Unmatched right curly bracket at ./delete-queue line 9, at end of line
    (Might be a runaway multi-line ;; string starting on line 5)
    syntax error at ./postfix-delete.pl line 9, near “}”
    Execution of ./postfix-delete.pl aborted due to compilation errors.

    I’m more of a PHP person so Perl’s not my thing. I know syntax is really important and I’ve double and triple checked to make sure things are correct, including composing in vi, pico and bbedit editors.
    ??

  3. Wow This is a seriously crappy coding job. Who writes this stuff? I cleaned this up to not only make sure this was scoped correctly, but also try to have a novice perl user understand it.

    #!/usr/bin/perl

    my $REGEXP = shift(@ARGV) || die “no email-adress given (regexp-style, e.g. [email protected])!”;

    my %Q;
    my $queue_id;
    my @data = `/usr/sbin/postqueue -p`;
    foreach my $line (@data) {
    if ($line =~ /^(w+)(*|!)?s/) {
    $queue_id = $1;
    }
    if($queue_id) {
    if ($line =~ /$REGEXP/i) {
    $Q{$queue_id} = 1;
    $queue_id = “”;
    }
    }
    }

    open(POSTSUPER,”|postsuper -d -“) || die “couldn’t open postsuper” ;

    foreach my $key (keys %Q) {
    print POSTSUPER “$keyn”;
    }
    close(POSTSUPER);

    Hopefully this helps.. I cannot confirm that this works, just cleaned it up so that it makes sense.

  4. If a queue_id of – is specified, the program reads queue IDs from standard input. For example, to delete all mail with exactly one sender [email protected] :

    mailq | tail +2 | grep -v '^ *(' | awk  'BEGIN { RS = "" }
                  # $7=sender, $8=recipient1, $9=recipient2
                   { if ($7 == "[email protected]")
                   print $1 }
                  ' | tr -d '*!' | postsuper -d -
  5. Some say Perl is becoming a lost art 😉 Here is my Ruby re-write (a bit more efficient. it uses practically no memory)

    Save as postfix-purge-queue and run every 1 min from a cron job.

    Change the path to match your own binaries. This assumes Solaris (+ blastwave) paths:

    #!/opt/csw/bin/ruby
    # vi: ft=ruby :
    #
    #  !! lemsx1 $$@$$ gmail !! com
    # 2010-03-04 12:20 EST
    #
    # Cleans postfix mail queue on Solaris
    
    # set debug to true when testing regex:
    debug = false
    
    regex = "example.(com|net|org)|Hosts+ors+domains+names+nots+found"
    
    IO.popen("/opt/csw/sbin/postqueue -p") do |readme|
        q_id = nil
        readme.each do |line|
            if line =~ /^(w+)(*|!)?s/
                q_id = $1
            end
            if q_id
                if line =~ /#{regex}/
                    if debug
                        puts "matching #{q_id}"
                    else
                        `/opt/csw/sbin/postsuper -d #{q_id} > /dev/null 2>&1`
                    end
                q_id=nil
                end
            end
        end
    end
  6. I use Fedora and had problems running this script. I replaced with this line

    open(POSTSUPER,”|/usr/sbin/postsuper -d -“) || die “couldn’t open postsuper” ;

    and it worked fine.

    Thanks!

  7. All scripts in this thread are gonna FAIL because the lines provided by “postqueue -p” can generate the following two lines, being the second an explanation of the first:
    0EE281EAE6C 78231 Mon Jan 16 00:35:08 [email protected]
    (line including for some reason a mail from yahoo, like [email protected] )

    and if you run it against the domain .[email protected], the script is gonna delete the entry from domain [email protected], when it shouldn’t.

    To solve it, you should have this:

      if (/^(w+)(*|!)?s/) {
         $queue_id = $1;
      } else {
         $queue_id = "";
      }
    
    Instead of just this:
      if (/^(w+)(*|!)?s/) {
         $queue_id = $1;
      } else {
         $queue_id = "";
      }
    

    (The mighty Ruby script will fail for the same reason, and is gonna be fixed as well with the “else” help)

  8. Hi Vivek,
    Could you please guide me as to how to use the command to kill all the queue mails in the post fix, Sorry I am new to Linux and Perl, I have no idea what i am dealing with please help me out, Following your instruction above i created the perl file, when i tried the command ./postfix-delete.pl yahoo.com i received the error that
    [email protected]:/etc/perl# delete.pl yahoo.com
    -bash: delete.pl: command not found.
    Can anyone please help me out with this, I am receiving 25000 spams everyday.

Leave a Comment