Long queue IDs in Postfix

Alvaro Marín alvaro at hostalia.com
Mon Aug 29 13:57:32 UTC 2016


Hi,

I've this issue opened in github:

https://github.com/MailScanner/v5/issues/15

I've enabled long_queue_ids in Postfix (with hash_queue_depth disabled)
and MailScanner works fine, but when it requeues the message, it creates
one message with a short queue ID format:

MailScanner[14209]: Requeue: 3sK7N64rr3zJX5T.A6FFB to D74D7218040

The HDOutFileName function generates it in Postfix.pm:

$file = sprintf("%05X%lX", int(rand 1000000)+1, (stat($file))[1]);

that should be in a long format.
Reading Postfix's code, I see:

/*

The long non-repeating queue ID is encoded in an alphabet of 10 digits,
21 upper-case characters, and 21 or fewer lower-case characters. The
alphabet is made "safe" by removing all the vowels (AEIOUaeiou). The ID
is the concatenation of:
- the time in seconds (base 52 encoded, six or more chars),
- the time in microseconds (base 52 encoded, exactly four chars),
- the 'z' character to separate the time and inode information,
- the inode number (base 51 encoded so that it contains no 'z'). */

So I've created a patch that implements this functionality (if long
queue ids format is enabled, if not, it will be generated as usual).

I'm running MailScanner-4.84.5-3 (with the patch to manage long queue
IDs from 4.85.1-1 version) and it runs fine (the patch attached is done
against last stable release code of MailScanner); I'll be watching it
for some days.

Regards,
-- 
Alvaro Marín Illera
Hostalia Internet
www.hostalia.com

-------------- next part --------------
--- Postfix.pm.orig	2016-08-29 15:27:32.364989625 +0200
+++ Postfix.pm	2016-08-29 15:30:59.896981402 +0200
@@ -246,9 +246,83 @@
 
     # Bad hash key $file = sprintf("%05X%lX", time % 1000000, (stat($file))[1]);
     # Add 1 so the number is never zero (defensive programming)
-    $file = sprintf("%05X%lX", int(rand 1000000)+1, (stat($file))[1]);
+    #$file = sprintf("%05X%lX", int(rand 1000000)+1, (stat($file))[1]);
     #print STDERR "New Filename is $file\n";
 
+    #
+    # Alvaro Marin alvaro at hostalia.com - 2016/08/25
+    # 
+    # Support for Postfix's long queue IDs format (enable_long_queue_ids).
+    # The name of the file created in the outgoing queue will be the queue ID. 
+    # We'll generate it like Postfix does. From src/global/mail_queue.h :
+    #
+    # The long non-repeating queue ID is encoded in an alphabet of 10 digits,
+    # 21 upper-case characters, and 21 or fewer lower-case characters. The
+    # alphabet is made "safe" by removing all the vowels (AEIOUaeiou). The ID
+    # is the concatenation of:
+    #
+    # - the time in seconds (base 52 encoded, six or more chars),
+    # 
+    # - the time in microseconds (base 52 encoded, exactly four chars),
+    # 
+    # - the 'z' character to separate the time and inode information,
+    #
+    # - the inode number (base 51 encoded so that it contains no 'z').
+    #
+    #
+    # We don't know if Postfix has long queue IDs enabled so we must check it 
+    # using the temporaly filename:
+    # Short queue IDs: /var/spool/postfix/incoming/temp-14793-6773D15E4E9.A3F46
+    # Long queue IDs: /var/spool/postfix/incoming/temp-17735-3sK9pc0mftzJX5P.A38B9
+    #
+    if ($file =~ /\-[A-Za-z0-9]{15}\.[A-Za-z0-9]{5}$/) {
+        # Long queue IDs
+        use Time::HiRes qw( gettimeofday );
+        my ($seconds, $microseconds) = gettimeofday;
+        my @BASE52_CHARACTERS = ("0","1","2","3","4","5","6","7","8","9",
+                                "B","C","D","F","G","H","J","K","L","M",
+                                "N","P","Q","R","S","T","V","W","X","Y",
+                                "Z","b","c","d","f","g","h","j","k","l",
+                                "m","n","p","q","r","s","t","v","w","x","y","z");
+        my $encoded;
+        my $file_out;
+        my $count=0;
+        while ( ($seconds > 0) && ($count < 6)) {
+                $encoded.=$BASE52_CHARACTERS[$seconds%52];
+                $seconds/=52;
+                $count++;
+        }
+        $file_out=reverse substr($encoded,0,6);
+        $encoded='';
+        $count=0;
+        while ( ($microseconds > 0) && ($count < 4)) {
+                $encoded.=$BASE52_CHARACTERS[$microseconds%52];
+                $microseconds/=52;
+                $count++;
+        }
+        $file_out.=reverse substr($encoded,0,4);
+
+        $file_out.="z";
+
+        my $inode=(stat("$file"))[1];
+        $encoded='';
+        $count=0;
+        while ( ($inode > 0) && ($count < 4)) {
+                $encoded.=$BASE52_CHARACTERS[$inode%51];
+                $inode/=51;
+                $count++;
+        }
+        $file=$file_out.reverse substr($encoded,0,4);
+        #print STDERR "long_queue_id: New Filename is $file\n";
+    }
+    else {
+        # Short queue IDs
+        # Bad hash key $file = sprintf("%05X%lX", time % 1000000, (stat($file))[1]);
+        # Add 1 so the number is never zero (defensive programming)
+        $file = sprintf("%05X%lX", int(rand 1000000)+1, (stat($file))[1]);
+        #print STDERR "New Filename is $file\n";
+    }
+
     if ($MailScanner::SMDiskStore::HashDirDepth == 2) {
       $file =~ /^(.)(.)/;
       return ($dir,$1,$2,$file);


More information about the MailScanner mailing list