Postfix : Conditional Header Checks

postfixsmtp

Here is my SMTP situation.

Mail flow is tagged by an online relay provider (!!SPAM!!, !!BULK!!, etc)

Mail flow is received by an internal postfix. Transport is configured to relay to our internal Exchange else if subject are tagged. I do that using Header_checks. The tagged mail flow is dispatched to our quarantine server (webUI for individual users etc …)

/^[sS]ubject:.*!!SPAM!!*/ FILTER smtp:192.168.11.250
/^[sS]ubject:.*!!BULK!!*/ FILTER smtp:192.168.11.250
/^[sS]ubject:.*!!SUSPECT!!*/ FILTER smtp:192.168.11.250

It works fine.
Our quarantine server can generate a list of trusted sender for users.
This whitelist is availlable and I can download it to my postfix.

My question is: how can I apply my whitelist before the header checking ?

 If Subject contains *!!SPAM!!*
  then
   If from contains trustedsender@domain.com AND if to contains InternalUser@domain.com
    Then redirect to internal exchange server
    else redirect to quarantine server
  endif
 endif

I don't know how to do that. Any hints?

Best Answer

After comment from @masegaloeh I've found a solution. The idea is to have a second postfix SMTP server listening on 10025 with a policy server in order to send mails to the normal server (if whitelisted) or to the quarantine server.

The idea was starting as your header_checks solution, in main.cf:

header_checks = regexp:/etc/postfix/header_checks

In header_checks:

/^(S|s)ubject: .*!!(SPAM|BULK|SUSPECT)!!.*/ FILTER  smtp:127.0.0.1:10025

Then in master.cf (edited with @masegaloeh comments):

10025      inet  n       -       n       -       -       smtpd
        -o receive_override_options=no_header_body_checks
        -o smtpd_recipient_restrictions=${my_switcher_restrictions}
policy  unix    -       n       n       -       0       spawn   user=nobody argv=/etc/postfix/policy-server-switcher

This makes the second instance of postfix override the use of header_checks.

And in main.cf

my_switcher_restrictions = check_policy_service unix:private/policy

And the contents of policy-server-switcher

!/bin/bash

sender=""
recipient=""

while read line
    do
    key=$(echo $line | cut -f1 -d=)
    value=$(echo $line|cut -f2 -d=)
    if [ "$key" == "sender" ] 
        then
        sender=${value}
        logger -p mail.info -t PolicyServer "Sender is: ${value}"
        fi
    if [ "$key" == "recipient" ] 
        then
        recipient=${value}
        logger -p mail.info -t PolicyServer "Recipient is: ${value}"
        fi
    if [  "x${recipient}" != "x" ] && [  "x${sender}" != "x" ]
        then
        if [ "$sender" == "alphamikevictor@serverfault.com" ] && [ "$recipient" == "alphamikevictor@example.com" ]
            then
            echo "action=FILTER smtp:192.168.1.150"
            echo
            exit 0
            fi
        if [ "$sender" == "thomas@serverfault.com" ] && [ "$recipient" == "thomas@example.com" ]
            then
            echo "action=FILTER smtp:192.168.1.150"
            echo
            exit 0
            fi
        echo "action=FILTER smtp:192.168.1.151"
        echo
        exit 0
        fi
    done

Of course you will need to program your policy server to load the whitelist from database or LDAP, here is just an example to get the idea.

But this still have some caveats, suppose I send a mail with this

From: thomas@serverfault.com

To: alphamikevictor@example.com

To: thomas@example.com

This will go to the normal server for alphamikevictor and for thomas, as far as the last test against the policy server returns FILTER to the normal, but if you place alphamikevictor on second position then it will send mail for both recipients to quarantine.