Troubleshooting Postfix header_checks: Why Regex Filters Fail and How to Fix Them


4 views

Postfix's header_checks functionality is a powerful spam filtering tool that examines message headers against regular expression patterns. The configuration you've shown:

header_checks = regexp:/etc/postfix/header_checks

is technically correct, but several factors could prevent it from working as expected.

Your question about the /i modifier is valid. While many regex engines support this flag, Postfix's implementation has limitations:

# This works in most regex engines but not in Postfix:
/^Subject:.*viagra.*/i DISCARD

# Postfix alternative (character classes):
/^Subject:.*[vV][iI][aA][gG][rR][aA].*/ DISCARD

Several issues could explain why your filters aren't catching test emails:

  • Header folding: Email clients often split long headers across multiple lines
  • Character encoding: Non-ASCII characters might bypass simple pattern matching
  • Header order: The From: header might appear after Subject: in actual messages

For different handling of spam messages, consider these alternatives:

# Reject with 550 error (bounces to sender)
/^Subject:.*viagra.*/ REJECT Spam detected

# Redirect to spam folder (requires maildir support)
/^Subject:.*pills.*/ REDIRECT spam@yourdomain.com

# Tag message header (doesn't block but marks it)
/^From:.*spammer.com/ WARN Possible spam source

To verify your filters without sending real emails:

postmap -q "Subject: cheap VIAGRA" regexp:/etc/postfix/header_checks

Remember to reload Postfix after configuration changes:

postfix reload

For more robust spam filtering, combine header_checks with other techniques:

# Match multiple variations
/^Subject:.*(viagra|cialis|levitra).*/ DISCARD

# Handle base64 encoded subjects
/^Subject:.*=\?.*viagra.*\?=/ DISCARD

# Check multiple headers in one rule
/^(From|Subject|Reply-To):.*pharmacy.*/ DISCARD

When implementing spam filtering in Postfix using header_checks, I encountered unexpected behavior where emails containing spam keywords in subjects weren't being filtered properly. Here's my original configuration:

# main.cf
header_checks = regexp:/etc/postfix/header_checks

The current regex patterns in /etc/postfix/header_checks appear correct at first glance:

/^Subject:.*viagra.*/i DISCARD
/^Subject:.*pills.*/i DISCARD
/^Subject:.*f\\*ckbuddy.*/i DISCARD
/^Subject:.*f\\*ckfriend.*/i DISCARD
/^Subject:.*f\\@ck.*/i DISCARD

/^From:.*viagra.*/i DISCARD

I conducted tests by sending emails from Hotmail containing these keywords in various cases (e.g., "ViAgRa", "PILLS") but the messages weren't being filtered. Here's what I discovered:

After making changes to header_checks, you must properly reload Postfix:

sudo postfix reload

Or alternatively:

sudo systemctl reload postfix

Instead of DISCARD, you can use REJECT to return a message to sender:

/^Subject:.*viagra.*/i REJECT Spam detected

To verify Postfix is actually processing your header_checks:

sudo postconf -n | grep header_checks
sudo postconf -e "header_checks = pcre:/etc/postfix/header_checks"
sudo postmap -q "Subject: viagra special offer" pcre:/etc/postfix/header_checks

For more powerful pattern matching, consider using PCRE instead of regexp:

header_checks = pcre:/etc/postfix/header_checks

With corresponding syntax changes in your patterns file.

The /i modifier is indeed supported in Postfix regex patterns. The issue likely stems from either:

  • Not properly reloading Postfix after changes
  • Mail client header variations
  • MIME encoding in subjects

Here's a verified working configuration:

# /etc/postfix/main.cf
header_checks = pcre:/etc/postfix/header_checks

# /etc/postfix/header_checks
/^Subject:\s*.*viagra.*/i REJECT Spam detected
/^Subject:\s*.*(pills|pharmacy|cialis).*/i DISCARD
/^From:.*@spamdomain\.com$/ REJECT Known spam source