How to reinject scanned mail into the queue using sendmail

emailpostfixsmtp

I would like to pass incoming mail using virtual_transport to a transport spamassassin (main.cf: virtual_transport=spamassassin) and then reinject the scanned mail into postfix using sendmail.

The transport looks like this:

spamassassin unix   -    n     n   -   -    pipe
    flags=hu user=vmail:mail argv=/usr/bin/spamc -u ${recipient} -e /usr/sbin/sendmail -f ${sender} ${recipient}

This should be possible acording to the postfix documentation:

High volume sites should avoid using "simple" content filters that
re-inject scanned mail via Postfix sendmail(1) and postdrop(1).

With my current sendmail call /usr/sbin/sendmail -f ${sender} ${recipient}, the mail loops by getting passed back into the queue and then back to spamassassin and so on.

From my understanding of the postfix documentation, mail delivered using postfix sendmail is dropped in the maildrop directory and then picked up using pickup. I tried to append a -o virtual_transport=dovecot to the pickup transport to avoid the queue, but this didn't help. (Those options can only get appended to smtp transports I suppose).

How can I reinject mail scanned with spamassassin back into the queue for final delivery without causing a loop?

Best Answer

How can I reinject mail scanned with spamassassin back into the queue for final delivery without causing a loop?

NO You can't

Explanation

I understand the reason you use virtual_transport to pipe email into Spam Assassin. You only want to scan the email intended to your virtual_mailbox_domain. Unfortunately it doesn't follow the recommended setup for simple content filter that using content_filter parameter instead virtual_transport.

Why I can't pass virtual_transport to pickup or smtpd?

Generally, here the email journey across postfix code

Input  --> cleanup --> qmgr --> Output 
*smtpd                          *local     
*pickup                         *virtual
*qmqpd                          *smtp
                                *lmtp
                                *pipe

In cleanup daemon, postfix will 'route' your email, whether they are belong to virtual, local, smtp or other transports. One exception is when non-blank content_filter parameter was passed into input service (smtpd, pickup, qmqpd). When this happened, postfix will override the message route and send the email into content_filter instead.

Another note, by default all postfix service was get parameter value from main.cf unless you override it by using -o parameter=value on master.cf. But not every parameter in man 5 postconf used by a service. For example, content_filter only used by pickup, smtpd and qmqpd so you can put -o content_filter=amavis:[127.0.0.1:10025 on them. Another example, it is not sensible to put -o smtp_bind_address in smtpd as this parameter only used in smtp service.

The same argument can be applied to your question, "why I can pass -o virtual_transport in pickup?"

So here are the several alternatives for your setup

  • Use content_filter as explained in postfix documentation. The downside is you also scan the email that relayed outside your domain.

  • Use content_filter via ACCESS table and FILTER action. With this way, you can selectively scan the incoming email. Unfortunately you must enlist your virtual domain again in that table.. You can avoid it by carefully placing ACCESS table after permit_mynetworks, permit_sasl_authenticated. With this way, outgoing email will be already permitted and you only scan incoming email. (Credit to OP comment :) )

  • Using Postfix Multiple Instance. With this way, you can keep the virtual_transport parameter and spamc will inject the email to your second instance. And then you can define different virtual_transport in different instance. But it's a bit overkill if you want to keep your setup simple.