How to Modify Sender Address in Postfix Queue Files Without Corrupting Messages


2 views

In modern Postfix installations (version 2.11+), the queue directory structure differs from older versions. The main queue directories are located in /var/spool/postfix/ instead of the traditional /var/spool/mqueue. The critical directories for this operation are:

deferred/  # Stores queued messages
corrupt/   # Holds messages that failed integrity checks
active/    # Currently being processed messages

When you directly modify queue files in deferred/ using text editors like vi, Postfix's integrity checks will detect the changes and move the files to corrupt/. This happens because:

  • Queue files contain metadata checksums
  • Message headers and body are stored in specific formats
  • Postfix maintains strict file permissions (root:postfix)

Instead of direct editing, use Postfix's built-in tools to safely modify queued messages:

# First, put all messages on hold
postsuper -h ALL deferred

# Then process each message individually
for qid in $(postqueue -p | grep '^[A-F0-9]' | awk '{print $1}'); do
    # Extract message and modify sender
    postcat -q $qid > message.txt
    sed -i 's/old-sender@wrong.com/new-sender@correct.com/g' message.txt
    
    # Reinject with modified sender
    postdrop -r new-sender@correct.com < message.txt
    
    # Remove original message
    postsuper -d $qid
done

For more precise control over header modifications:

# View message structure
postcat -q QUEUE_ID

# Modify only envelope sender (works for some cases)
postsuper -r "old@domain.com" -s "new@domain.com" QUEUE_ID

Before performing bulk modifications:

  • Backup your queue: cp -a /var/spool/postfix /root/postfix_queue_backup
  • Test with a single message first
  • Monitor syslog for errors: tail -f /var/log/mail.log
  • Consider message headers like Return-Path and Received

For queues with thousands of messages, this Perl script can help:

#!/usr/bin/perl
use strict;
use warnings;

my $queue_dir = '/var/spool/postfix/deferred';
opendir(my $dh, $queue_dir) or die $!;

while (my $file = readdir $dh) {
    next unless $file =~ /^[A-F0-9]+$/;
    
    my $qid = $file;
    system("postsuper -h $qid");
    
    open(my $fh, '-|', "postcat -q $qid") or die $!;
    my @lines = <$fh>;
    close $fh;
    
    foreach (@lines) {
        s/old-domain\.com/new-domain\.com/g;
    }
    
    open(my $out, '>', '/tmp/modified_msg') or die $!;
    print $out @lines;
    close $out;
    
    system("postdrop -r new-sender\@domain.com < /tmp/modified_msg");
    system("postsuper -d $qid");
}

closedir $dh;

Recent versions of Postfix (2.11.0+) store queued messages differently than older versions. Instead of the traditional /var/spool/mqueue, we now find messages distributed across several directories under /var/spool/postfix/. The main directories containing queued emails are:

active/
deferred/
hold/
corrupt/

When you attempt to modify queued messages directly in the deferred directory using text editors like vi, Postfix marks them as corrupt because:

  • The queue files contain binary headers alongside message content
  • Postfix maintains checksums that become invalid after manual edits
  • The internal message structure gets disrupted by direct modifications

Instead of editing files directly, use these Postfix-compatible methods:

Method 1: Using postsuper and postcat

# First, hold all messages you want to modify
postsuper -h $(postqueue -p | grep "wrong@domain.com" | awk '{print $1}')

# Extract message content
postcat -q MESSAGE_ID > message.txt

# Edit the sender in message.txt (remember to keep headers intact)

# Delete the original message
postsuper -d MESSAGE_ID

# Inject the modified message
sendmail -f correct@domain.com recipient@example.com < message.txt

Method 2: Using qmqp-source (for bulk changes)

# Install qmqp-source if not available
apt-get install postfix-utils

# Create a modification script
cat << 'EOF' > modify_sender.sh
#!/bin/bash
msgid=$1
tempfile=$(mktemp)
postcat -q $msgid > $tempfile
sed -i '/^From:/ s/wrong@domain.com/correct@domain.com/' $tempfile
postsuper -d $msgid
sendmail -f correct@domain.com -t < $tempfile
rm $tempfile
EOF

# Apply to all queued messages
postqueue -p | awk '/wrong@domain.com/ {print $1}' | xargs -n1 ./modify_sender.sh

For future messages, configure sender rewriting in main.cf:

smtp_generic_maps = hash:/etc/postfix/generic

Then create /etc/postfix/generic:

wrong@domain.com correct@domain.com
@wrongdomain.com @correctdomain.com

Remember to run postmap /etc/postfix/generic and systemctl reload postfix after changes.

After making changes:

# Check queue status
postqueue -p

# Force queue processing
postqueue -f

# View specific message
postcat -q MESSAGE_ID | less

Always test changes with a small subset of messages before applying to the entire queue.