Default Virtualmin postfix configuration causes backscatter spam

Summary: The default virtualmin postfix config causes backscatter spam and a solution is needed. None of the solutions I tried worked.

My IP address was recently blacklisted at Usually this is because mail to non-existent users (such as typo@mydomain) is bouncing back to fictitious senders instead of being rejected or discarded, but Virtualmin configures that pretty well. In my case, incoming spam was being forwarded to a third party which rejected it immediately and my postfix server tried to inform the fictitious senders with a bounce message that seemed to come from me. This is bad and I’m surprised postfix (and virtualmin) is configured like this by default.

The possible solutions I can see are:

  1. Use spamassassin to reject incoming spam before it is forwarded. I don’t like this because I don’t store mail, I only forward it and spamassassin can cause false positives and false negatives. (I did nevertheless try enabling spamassassin but with disastrous results, see separate thread.)

  2. Check that the third party server will accept forwarded mail before completing the incoming transfer. Postfix can be configured to do this as described in but it slows things down and has limitations.

  3. Filter out third-party bounces and discard them as described in This looks promising but I couldn’t get it to work, even with a bounce message that contained the correct trigger. Perhaps something’s wrong with the regex or with header filtering?

  4. Use spamassassin to filter out the third-party bounces. This has other benefits as described at so I tried enabling spamassassin including the “Virus-bounce ruleset”. I couldn’t get that to work either.

  5. Configure postfix to prevent it sending to any address that’s not on a white list of “forward to” addresses. That would prevent mailing lists working and would require a lot of maintenance so I haven’t tried it.

Has anyone found a solution that works? I’ve googled extensively and spent hours on this without success.

I’m wondering here… Isn’t this expected behavior? If you configure your Postfix as a forwarding-only system without any spam checks, it will first fully receive the message, close the incoming connection, and then try to forward it. That’s simply because receiving, sorting and processing (delivery attempt) are separate processes and cannot be done in one step.

When the system you’re trying to forward to then rejects the mail, your Postfix has no chance but to send an NDR to the apparent original sender, since its SMTP session has already been closed.

Yes, that’s exactly how it was designed. Then the spammers discovered they could forge the sender address and get their spam out that way, which means it’s now worse than useless. So we either have to reject the message while the incoming connection is still open, or not at all.

I tried options 2 (address verification) and 3 (discard 3rd party bounces) in my original post but I can now report that they don’t stop the backscatter. Nor does option 4 (spamassassin). In all cases I think the problem is that the backscattered message is triggered not by an email message that can be parsed, but by a delivery rejection.

I had an “aha!” moment when I thought the problem might be due to procmail rather than postfix when I read this gmail article:

However, I tried implementing that change and it hasn’t worked either. :frowning:

Just to summarise, the changes I’ve tried without success are:

  1. Edit ‘/etc/postfix/header_checks’, and add these lines:
    /^Content-Type: multipart/report; report-type=delivery-status;/ REJECT no third-party DSNs
    /^Content-Type: message/delivery-status; / REJECT no third-party DSNs
    Edit ‘/etc/postfix/’, and ensure it contains:
    header_checks = regexp:/etc/postfix/header_checks
    Restart postfix

  2. Edit ‘/etc/postfix/’ to add reject_unknown_recipient_domain and reject_unverified_recipient:
    smtpd_recipient_restrictions = permit_sasl_authenticated reject_unauth_destination reject_unknown_recipient_domain reject_unverified_recipient
    Restart postfix

  3. Enable spamassassin in Virtualmin (Features and Plugins, and the domain in question)

  4. Add the following to my procmail config file
    SENDER=formail -c -x Return-Path

The two things I tried that didn’t work were:

  1. The “bounce-never” command filter option described at
    smtpd_command_filter = pcre:/etc/postfix/command_filter

# Bounce-never mail sink. Use notify_classes=bounce,resource,software
# to send bounced mail to the postmaster (with message body removed).
/^(RCPT\s+TO:.?)\bNOTIFY=\S+\b(.)/ $1 NOTIFY=NEVER $2
This sort of works, but floods the postmaster with bounces.

  1. The “soft-bounce” option also described at This also sort of works, but fills the mail queue with bounces.

The thing I tried that DID work (touch wood) was:

  1. Set bounce unix - - n - 0 discard
    in /etc/postfix/
    as described in
    Mail for valid users is accepted (and forwarded), mail for non-existent users is rejected and everything else is discarded, never bounced.

The downside is that mail that is forwarded to a third party such as gmail but not delivered for whatever reason may silently vanish, unlike mail sent directly to gmail without going through my server which would show a rejection reason. I know of no possible solution to that which doesn’t involve backscatter and hence blacklisting as previously, or the possibility of valid mail occasionally disappearing without warning (the spamassassin solution).

I’ve made some progress so I thought I’d update the thread.

Setting the bounce handler to “discard” does effectively prevent backscatter problems but is not an ideal solution because you sometimes need to see the bounce messages.

I actually contacted Wietse Venema (postfix architect) about this but his only advice was to enable spam filtering so spam doesn’t get forwarded in the first place. The problem is spam filtering is never perfect so some spam still gets through - and even worse, false positives stop some genuine mail getting through. And filtering in the forwarding server prevents the end user doing any bayesian training. At the time I couldn’t get spam filtering working on forwarded mail anyway and Wietse was quite rude about it so I gave up.

I have now discovered how to make spam filtering work on forwarded messages - you have to set up a filter in Usermin (which I wasn’t using before, since my users don’t use local mail storage). The problem is, the CPU load it caused (even running as a daemon, with local DNS resolution etc.) was bringing my VPS to its knees.

To cut a long story short, I ended up moving to a more expensive hosting provider ( that had a more up to date OS (and KVM hypervisor) that allowed me to run the postfix postscreen module. This has greatly reduced the volume of spam flowing through my system, which in turn has reduced backscatter. The other big benefit is that mail is getting through more reliably to big providers like Gmail and AOL who sometimes blacklist servers that forward too much spam.

So my advice is to enable postscreen if possible if you’re forwarding mail. It’s a bit fiddly to set up (you’ll probably need to register at barracuda, for example) and it can cause genuine mail to be delayed sometimes, a bit like greylisting. But on the whole it makes a big difference without causing false positives.

Excellent work philmck.

Would you have virtualmin postscreen enabling and config steps to share ?

Good point - basically I just followed the instructions here, including enabling, and

The spam messages reaching my personal account dropped from around 800/day to 5/day just by doing this! Be aware that a LOT of log messages will be generated in the process, and there’s no way to disable them.

By the way, I put a more general Virtualmin tutorial on my web site at if that helps.

Oh, and to get forwarded mails to be filtered by Spamassassin and ClamAV you need to first enable them in Virtualmin > System Settings > Feature and Plugins, then make any adjustments in Virtualmin > Email Messages > Spam and Virus Scanning (select whether to run as daemons or not).

Then select every individual user one by one (it took me hours) and under Mail Forwarding settings select “Deliver to this user normally” (and remove any existing forwarding, perhaps cutting the addresses to your clipboard). Then click the “Login to Usermin” button and select “Forward Email” and select “Email forwarding enabled” and paste the desired forwarding addresses there.

Then click Email Filters > Add a new email filter and select All email, Perform spam classification, Continue with other filter rules and click Create. Move this rule to the top of the list.

Should this Postscreen enabling/configuring functionality be added to Virtualmin’s “Email Messages/ Spam and Virus Scanning” module ? Seems like all the nitty gritty could be better handled automatically and result in minutes rather than hours of downtime, with less chance of messing up the postfix config files ?

In case anyone finds this old thread, I’ve found some problems with forwarding using Usermin that make it less than useful. By default bounce messages are suppressed and they must be, otherwise you can get forwarding loops (as I discovered the hard way). But this means user’s aren’t aware if forwarded mail delivery fails at the destination. Also, certain “magic” addresses such as the useful admin@ never get forwarded at all.

The solution for me was to do the forwarding in virtualmin rather than usermin. This is simpler in many ways but it does bring us back to the original problem mentioned in this thread - Gmail rejects the forwarded messages because the spam filtering headers haven’t been added yet.

The solution for me was to install Amavisd-new to control the spam and virus filtering before messages get forwarded. This works really well (less spam getting through) but there’s no webmin module for it so you have to set it up from the command line.

So, to come back to the topic of backscatter spam and postscreen - yes, I definitely think postscreen support should be added to Webmin, along with Amavis support. And while we’re at it, postsrsd support as well because otherwise SPF will break for forwarded mail.

@philmck Would you mind sharing your amavisd-new setup and what was necessary to make it work with Virtualmin?

Sure, here are instructions (excerpted from my tutorial at

Amavis spam filtering is easy to install from standard Ubuntu packages:

sudo apt-get install amavisd-new pyzor razor opendkim postfix-policyd-spf-python
sudo apt-get install arj cabextract lhasa nomarch rar

It must be enabled by uncommenting these lines in file /etc/amavis/conf.d/15-content_filter_mode

@bypass_spam_checks_maps = (
%bypass_spam_checks, @bypass_spam_checks_acl, $bypass_spam_checks_re);

In file /etc/amavis/conf.d/50-user I add the following lines so that only the most severe spam is discarded and the rest is passed through (not quarantined) so users can see it in their Spam folder and drag it to their Inbox to train their spam filter if necessary.

$sa_kill_level_deflt = 10; # triggers spam evasive actions

$clean_quarantine_to = undef; # local quarantine
$virus_quarantine_to = undef; # traditional local quarantine
$banned_quarantine_to = undef; # local quarantine
$bad_header_quarantine_to = undef; # local quarantine
$spam_quarantine_to = undef; # local quarantine
$sa_spam_subject_tag = '[SPAM, SCORE] ';

Prevents {RelayedOpenRelay} warning

@local_domains_maps = 1;

In file /etc/postfix/ add this:

PostfixAmavisNew - Community Help Wiki

content_filter = smtp-amavis:[]:10024

At the end of file /etc/postfix/ add this:

PostfixAmavisNew - Community Help Wiki

smtp-amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20 inet n - - - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks…

​ -o smtpd_milters=

Also add the following two lines immediately below the “pickup” transport service:

-o content_filter=
-o receive_override_options=no_header_body_checks

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.