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.