You've just installed postfix, badly, and emails to your users are not being delivered, but rather deferred. You are stuck in the meantime until you can figure out how to get the email to deliver, and meanwhile you have emails pending to be delivered to users. You'd rather not make them wait.

*resurrection* to the rescue. I wrote this quickly as a band-aid, but my config is still messed up and I'm still using this tool to purge "deferred"s until I can get my config rectified.

As written, you can use this from "cron" if you like!

The program takes no arguments. It scans the postfix queue looking for reason=deferred, and (added today) reason = User unknown in virtual alias table, and for each item found, converts the queue item into a valid email and appends it directly to the intended recipient's spool file. (Run "resurrection" as root.)

If it cannot open the spool file, it instead appends the content to a file SPOOL/username. You can hack the code
to put that directory where you like.

If the operation was successful, the spool file is moved out of /var/spool/postfix to a directory STASH, similar to
SPOOL. This removes the item from the postfix queue.

===

Here the code is (php7.)
The postfix guys can carp at my stupidisms, fair game. Meanwhile, this tool is helping save my ass. If you want to use this, eyeball all the paths used to insure they match use on your system.

*#!/usr/local/bin/php**
**<?php**
**// "resurrection" by Eric Dynamic, April 2019.**
**
**// items in STASH cannot be processed this way, as we must "postcat -hb STASH/$QID" and do not know the recipient,** **// we would have to get that from the "xpq" phase; the email can only be for one person; and other possible missing values.** **// (probably untrue: the source location differs, but -vq will return the same information no matter where the file comes from.)** **// postcat -vq gives recipient information (aliases translated.) postcat -hbq does not dress the output and we'd have to map aliases.**
**
**$QENTRY = array();**
**exec("postqueue -j",$QENTRY);**
**if(!count($QENTRY)) return;**
**$line_number = 0;**
**foreach($QENTRY as $J) {**
**    // one item in the postfix queue:**
**    ++$line_number; $L = "($line_number)";**
**    $QITEM = json_decode($J,TRUE);**
**    if(!is_array($QITEM)) { echo "$L QITEM is not an array.\n"; return; }**
**    if(!isset($QITEM)) { echo "$L no QITEM.\n"; continue; }**
**    if(!isset($QITEM['queue_name'])) { echo "$L no qname.\n"; continue; }**
**    if($QITEM['queue_name'] != 'deferred') continue;**
**    if(!isset($QITEM['queue_id'])) { echo "$L no QID.\n"; continue; }**
**    $QID = $QITEM['queue_id'];**
**
**// for each recip w/delay. decode msg once, send mult.**
**
**    if(!isset($QITEM['recipients'])) { echo "$L no recipient array.\n"; continue; }**
**    $USER = array();**
**    $uline_number = 0; $dunno = 1;**
**    foreach( $QITEM['recipients'] as $RCP ) {**
**        ++$uline_number; $U = "($uline_number)";**
**echo "\nobject $L$U\n";**
**var_dump($RCP);**
**        if($dunno) {    // we'll assume the reason is always given with the first user**
**            if(!isset($RCP['delay_reason'])) continue;**
**            if(**
**                !preg_match("/^temporary failure/",$RCP['delay_reason'])**
**                && !preg_match("/^User unknown in virtual alias table/",$RCP['delay_reason'])**
**                ) continue;**
**            // added 'unknown', note that this may deliver to a spool file for a nonexistent user**
**            // and you need to clean that up manually after this runs.**
**            $dunno = 0;**
**            }**
**        // ['sender']=> 'bou...@mcsv.net'**
**        if(!isset($RCP['address'])) continue;**
**        $u = strtok($RCP['address'],'@');**
**        if(!$u) continue;**
**        echo "$L$U user $u.\n";**
**        $USER[] = $u;**
**        }**
**    if(!count($USER)) { echo "$L no users for a temporary failure or unknown alias.\n"; continue; }**
**
**    echo "postcat -hbq $QID\n";**
**    $fd = popen("postcat -vq $QID","r");**
**    if(!$fd) { echo "$L no QF results.\n"; continue; }**
**////////////////////////////////////////////**
**// xpq**
**////////////////////////////////////////////**
**    $recipient = $from = $date = $BODY = ''; $token = array();**
**    while( $line = fgets($fd) ) {**
**        $line = rtrim($line);**
**//echo "line\t".substr($line,0,13)." = $line\n";**
**        if( substr($line,0,10) == "recipient:" ) { $recipient = substr($line,11); continue; }**
**        if( substr($line,0,13) != "regular_text:" ) continue;**
**        $line = substr($line,14);**
**//echo "frag\t\t".substr($line,0,6)."\n";**
**        if(substr($line,0,6) == "Date: ") $date = substr($line,6);**
**        else if(substr($line,0,6) == "From: ") $from = substr($line,6);**
**        $BODY .= "$line\n"; // actually, this contains the headers too**
**        }**
**    fclose($fd);**
**    if(!$recipient || !$from || !$date) { fprintf(STDERR,"missing recipient($recipient), from($from) or date($date).\n"); continue; }**
**
**    //regular_text: Date: 11 Apr 2019 19:02:05 -0000**
**    //regular_text: From: "Reader Supported News" <do-not-re...@inbound.readersupportednews.org>**
**    //From e...@transbay.net Sun Apr  7 15:11:13 2013**
**
**if(preg_match("/<(.*)>/",$from,$token)) $from = $token[1]; else { $j = strpos($from,' '); if($j) $from = substr($from,0,$j); }**
**
**    // we have to recreate the leading "^From " line to make mail programs happy** **    if(!preg_match("/([ 0-9][0-9]) ([ADFJMNOS][a-z][a-z]) (2[01][0-9][0-9]) ([0-9]{2}:[0-9]{2}:[0-9]{2})/",$date,$token))**
**        { fprintf(STDERR,"bad date format.\n"); return; }**
**    $date = $token[2].' '.$token[1].' '.$token[3].' '.$token[4];**
**    $DOW = date_parse_from_format("M j H:i:s Y",$date);                     // format expected** **    $DOW = date('D',mktime(0,0,0,$DOW['month'],$DOW['day'],$DOW['year']));**
**    $date = "$DOW  $date";***// all that to get the day of the week***
**    $EMAIL = "From $from $date\n$BODY\n";                                   // add a blank line in case mail programs need it**
**////////////////////////////////////////////**
**    // do xpq here into outfile $SPOOLFILE. once satisfied this works we will append to user's real spool file**
**    foreach($USER as $u) {**
**        $u = strtolower($u);**
**        //$F = "/usr/local/etc/postfix/SPOOL/$u";**
**        $F = "/var/mail/$u";**
**        $fp = fopen($F,"a"); if(!$fp) {**
**            echo "$L can't open $F for $QID output to $u. Fallback to SPOOL.\n";**
**            $F = "/usr/local/etc/postfix/SPOOL/$u";**
**            $fp = fopen($F,"a"); if(!$fp) { echo "$L can't open $F for $QID output to $u.\n"; continue; }**
**            }**
**        flock($fp,LOCK_EX);**
**fprintf($fp,"\n%s",$EMAIL); // a leading blank too to be paranoid**
**        flock($fp,LOCK_UN);**
**        fclose($fp);**
**        }**
**////////////////////////////////////////////**
**    // if we were happy, move the spool file out of postfix space**
**    $Q0 = substr($QID,0,1);**
**    $F = "/var/spool/postfix/deferred/$Q0/$QID";**
**    $S = "/usr/local/etc/postfix/STASH/$QID";**
**    @unlink($S);**
**    rename($F,$S);  // assuming postfix does not record the existence of the file thus needing to be told this was done**
**////////////////////////////////////////////**
**    }**
**?>**
*

Reply via email to