Enable and Configure Postscreen in Postfix to Block Spambots

In previous tutorials, we discussed how to set up a mail server from scratch on Linux (Ubuntu version, CentOS/RHEL version). This tutorial is going to show you how to enable and configure Postscreen in Postfix SMTP server. Postscreen is an SMTP filter that blocks spambots (or zombie machines) away from the real Postfix smtpd daemon, so Postfix does not feel overloaded and can process legitimate emails more efficiently.

Note: If you are using iRedMail or Modoboa, then Postscreen is enabled by default on your server. Still, you will learn something new.

Enable and Configure Postscreen in Postfix to Block Spambots

Reducing SMTP Server Overload

By default, Postfix can spawn up to 100 SMTP server processes to handle SMTP client connections. You can check the process limit by running the following command.

postconf default_process_limit

Sample output:

default_process_limit = 100

If spambots are constantly hitting your Postfix SMTP server, then there will be less Postfix SMTP server processes to accept legitimate email messages. And when the number of SMTP clients exceeds the number of Postfix SMTP server processes, other SMTP clients must wait until an SMTP server process becomes available.

By blocking spambots with Postscreen, we can save SMTP server processes for legitimate SMTP clients. Postscreen is designed as a first layer of defense against spammers. It is implemented as a single process listening on port 25 and can handle multiple inbound SMTP connections. It’s fast and lightweight, compared to using other SMTP-level access checks.

Measurements Used By Postscreen Against Spambots

Most spambots have faulty SMTP protocol implementation. Postscreen can take advantage of this fact and use several measurements to block spambots.

  • Pregreet test. If the SMTP client speaks before its turn, stop the connection.
  • Realtime blacklist check. If the SMTP client’s IP address is on a blaclist, such as Spamhaus, stop the connection.
  • Deep protocol test.

Step 1: Enable Postscreen in Postfix

Postscreen is first introduced in Postfix 2.8. If you are using any current Linux distribution, you should have Postfix 3.0 or above. To check your Postfix version, run

postconf mail_version

Sample output:

mail_version = 3.3.0

Edit the Postfix master configuration file.

sudo nano /etc/postfix/master.cf

Comment out the following line.

smtp      inet  n       -       y       -       -       smtpd

Then uncomment the following 4 lines.

smtp      inet  n       -       y       -       1       postscreen
smtpd     pass  -       -       y       -       -       smtpd
dnsblog   unix  -       -       y       -       0       dnsblog
tlsproxy  unix  -       -       y       -       0       tlsproxy

Where:

  • The first two lines enables Postscreen. Both Postscreen and the smtpd daemon will be listening on port 25. Postscreen will check the SMTP client first and then pass the connection to smtpd daemon.
  • The dnsblog (DNS Blacklist Logger) service enables logging of DNS blacklist checks.
  • The tlsproxy service enables STARTTLS support for postscreen, so remote SMTP clients can establish encrypted connection when Postscreen is enabled.

Save and close the file. (Don’t restart Postfix just yet.)

Create Permanent Whitelist/Blacklist

Edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

We need to add our own IP addresses to Postscreen whitelist, so that our own SMTP requests won’t be tested by Postscreen. Add the following two lines at the end of the file.

postscreen_access_list = permit_mynetworks cidr:/etc/postfix/postscreen_access.cidr
postscreen_blacklist_action = drop

Save and close the file. The permit_mynetworks value will whitelist any IP address listed in the mynetworks parameter. To check the value of mynetworks, run

postconf mynetworks

Sample output:

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

You can also manually add additional IP addresses in the /etc/postfix/postscreen_access.cidr file.

sudo nano /etc/postfix/postscreen_access.cidr

You might want to whitelist your mail server’s public IPv4 and IPv6 address. So I add the following lines in the file. Replace the IP addresses with your own. Note that you need to use the CIDR notation: For a single IPv4 address, add /32 at the end; For a single IPv6 address, add /128 at the end.

#permit my own IP addresses.
23.254.225.226/32             permit
2a0d:7c40:3000:b8b::2/128     permit

If your mail server also runs a VPN server, you may want to add the VPN server’s address to the whitelist. For example, my VPN server uses the 10.10.10.1 private IP address, so I add the following line in the file.

10.10.10.1/32                 permit

If you want to permanently blacklist an IP address, you can do so like below.

12.34.56.78/32                reject

Save and close the file. Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Note: Postscreen listens on port 25 only, so authenticated users from port 587 or 465 won’t be affected by Postscreen.

Postscreen itself also maintains a dynamic whitelist to minimize the delay for legitimate emails, defined by the postscreen_cache_map parameter.

postconf postscreen_cache_map

Sample output:

postscreen_cache_map = btree:$data_directory/postscreen_cache

Each IP address in the dynamic whitelist has a lifetime.

Step 2: Pregreet Test

There is a pregreet test in Postscreen to detect spam. As you may already know, in SMTP protocol, the receiving SMTP server should always declare its hostname before the sending SMTP server does so. Some spammers violate this rule and declare their hostnames before the receiving SMTP server does.

By default, Postscreen enables the pregreet test, but won’t do anything with the test result. As you can see from the following lines in my mail log (/var/log/mail.log or /var/log/maillog), the “PREGREET” text indicates the SMTP client declared its hostname first, but Postscreen still passed the connection to Postfix smtpd daemon.

mail postfix/postscreen[24075]: CONNECT from [156.96.118.171]:62604 to [23.254.225.226]:25
mail postfix/postscreen[24075]: PREGREET 11 after 0.07 from [156.96.118.171]:62604: EHLO User\r\n
mail postfix/smtpd[24076]: connect from unknown[156.96.118.171]
mail postfix/smtpd[24076]: disconnect from unknown[156.96.118.171] ehlo=1 quit=1 commands=2

To reject SMTP clients that violate this rule, edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following line at the end.

postscreen_greet_action = enforce

Save and close the file. Then restart Postfix.

sudo systemctl restart postfix

From now on, Postscreen will stop connection if an SMTP client violate this rule. As you can see the from the following log, Postscreen stopped the connection, so the spammer doesn’t have a chance to harass the smtpd daemon.

mail postfix/postscreen[6471]: CONNECT from [192.241.239.123]:48014 to [23.254.225.226]:25
mail postfix/postscreen[6471]: PREGREET 19 after 0 from [192.241.239.123]:48014: EHLO zg-0131a-136\r\n
mail postfix/postscreen[6471]: DISCONNECT [192.241.239.123]:48014

Postscreen still allow other tests to complete before stopping the connection. If you prefer to drop the connection immediately without doing other tests, use the following setting instead.

postscreen_greet_action = drop

Step 3: Using Public Blacklists & Whitelists

The postscreen_dnsbl_sites parameter can be used to check SMTP client’s IP address against public blacklists (DNSBL). You might be already using Postfix smtpd’s reject_rbl_client to reject an SMTP client if its IP address is on a public blacklist. However, that can cause false positives because an innocent SMTP server’s IP address could be on a blacklist for whatever reason, even if you use permit_dnswl_client to also check against public whitelist (DNSWL).

To reduce false positives, Postscreen allows you to check multiple blacklists and add weight factor to each blacklist. For example, if an IP address is on Spamhaus blacklist, add 3 points; if an IP address is on the BarracudaCentral blacklist, add 2 points. If the combined score is high enough (defined by postscreen_dnsbl_threshold), reject the SMTP client. This scoring system is similar to that of SpamAssassin.

In the following configuration, we set the threshold to 3 points. Spamhaus has weight of 3. BarracudaCentral has weight of 2. SpamCop has weight of 1. If the combined score is equal to or greater than 3, Postscreen would reject the SMTP client.

postscreen_dnsbl_threshold = 3
postscreen_dnsbl_action = enforce
postscreen_dnsbl_sites =
        zen.spamhaus.org*3
        b.barracudacentral.org=127.0.0.[2..11]*2
        bl.spameatingmonkey.net*2
        bl.spamcop.net
        dnsbl.sorbs.net

We can also use postscreen_dnsbl_sites to check SMTP client’s IP address against public whitelist (DNSWL). If a client’s IP address is on whitelist, add a negative score.

postscreen_dnsbl_sites =
        zen.spamhaus.org*3
        b.barracudacentral.org=127.0.0.[2..11]*2
        bl.spameatingmonkey.net*2
        bl.spamcop.net
        dnsbl.sorbs.net
       swl.spamhaus.org*-4,
       list.dnswl.org=127.[0..255].[0..255].0*-2,
       list.dnswl.org=127.[0..255].[0..255].1*-4,
       list.dnswl.org=127.[0..255].[0..255].[2..3]*-6

If you use Postfix smtpd’s reject_rbl_clientor permit_dnswl_client parameter, you should delete them now, so smtpd daemon won’t perform IP checks again after Postscreen. Postscreen doesn’t check domain name based blacklist/whitelist, so we should continue using reject_rhsbl to perform domain name lookup on public blacklists.

smtpd_recipient_restrictions =
     permit_mynetworks,
     permit_sasl_authenticated,
     ...
     ...
     reject_rhsbl_helo dbl.spamhaus.org,
     reject_rhsbl_reverse_client dbl.spamhaus.org,
     reject_rhsbl_sender dbl.spamhaus.org,

Save and close the Postfix main configuration file. Then restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Note: If see the following message in your mail log, it means the SMTP client’s IP address is not on the whitelist (list.dnswl.org). This is not an error.

warning: dnsblog_query: lookup error for DNS query 161.223.143.185.list.dnswl.org: Host or domain name not found. Name service error for name=161.223.143.185.list.dnswl.org type=A: Host not found, try again

If it’s on the whitelist, the message will look something like this:

postfix/dnsblog[21188]: addr xx.xx.xx.xx listed by domain list.dnswl.org as 127.0.10.0

If an IP address is listed as 127.0.0.255 on list.dnswl.org, like in following message, it means you have reached the query limit. You should run your own local DNS resolver.

postfix/dnsblog[11951]: addr 202.66.174.152 listed by domain list.dnswl.org as 127.0.0.255

Also note that BarracudaCentral Blocklist requires registration, which is free of charge. After creating an account, simply add the IP address of your DNS resolver and you are done.

Running Your own Local DNS Resolver

Note that you should set up a local DNS resolver on your mail server when using public blacklists and whitelists, because most of them have query limit. If you use public DNS resolver like 8.8.8.8, you will likely to reach the query limit sooner than you think.

Some Dead/Closed DNSBL sites

You should not use dead or closed DNSBL sites, or your mail server will reject legitimate emails.

  • dnsbl.njabl.org: has been offline since 2013.
  • dnsbl.ahbl.org: Public access to the list was terminated in 2015.

Step 4: Enable Deep Protocol Tests

There are 3 common deep protocol tests in Postscreen:

  • SMTP pipelining test
  • Non-SMTP command test
  • Bare newline test

Pipelining is an extension to the SMTP protocol. It allows the SMTP client to send multiple SMTP command at once without waiting for response from SMTP server. Postfix supports pipelining by default. To check, use telnet to connect to your mail server.

telnet mail.yourdomain.com 25

Then use the EHLO command to declare your hostname.

EHLO mail.google.com

The SMTP server’s response below indicates it support pipelining.

250-PIPELINING
250-SIZE 157286400
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

Then quit the connection.

quit

Some spammers would use command pipeling to issue multiple RCPT TO: commands at once, in order to send spam to multiple recipients in one SMTP session. If the SMTP server doesn’t announce pipelining support, then the SMTP client should not issue multiple commands at once.

Add the following two lines in /etc/postfix/main.cf file to enable pipeling test and reject SMTP clients that fail this test.

postscreen_pipelining_enable = yes
postscreen_pipelining_action = enforce

As the name suggests, non-SMTP command test makes Postscreen detect SMTP clients that send non-SMTP commands. Add the following two lines in /etc/postfix/main.cf file to reject such SMTP clients.

postscreen_non_smtp_command_enable = yes
postscreen_non_smtp_command_action = enforce

The bare newlines test allows Postscreen to detect SMTP clients that end a line with <LF>, instead of the standard <CR><LF>. Add the following two lines in /etc/postfix/main.cf file to reject such SMTP clients.

postscreen_bare_newline_enable = yes 
postscreen_bare_newline_action = enforce

Save and close the file. Then restart Postfix for the changes to take effect.

sudo systemctl restart postfix

The Greylisting Effect of Deep Protocol Tests

The limitation of deep protocol tests is that Postscreen would disconnect new SMTP clients no matter the tests are passed or not. Postscreen disconnects each client with the following message:

450 4.3.2 Service currently unavailable

And the client must try again later from the same IP address. This is effectively a form of greylisting, so you need to disable other forms of greylisting. For example, if you followed my previous tutorial to use Postgrey as the greylisting policy server, then find the following line in /etc/postfix/main.cf file and comment it out.

check_policy_service inet:127.0.0.1:10023,

Save and close the file. Then restart Postfix.

sudo systemctl restart postfix

How to Minimize Bad User Experience

Greylisting is rather annoying for the end user, as the user has to wait another several minutes for the email to arrive. To minimize this bad experience, there are 3 ways I can think of when using Postscreen deep protocol tests.

  • Create a second MX record that points to the same IP address.
  • If an SMTP client’s IP address is on a public whitelist, skip the deep protocol tests.
  • Use Postwhite to add known good IP addresses to the Postscreen whitelist.

Create a second MX record that points to the same IP address

You can specify more than one MX record for your domain name like below.

Record Type    Name      Mail Server            Priority

MX             @         mail.yourdomain.com     0
MX             @         mail2.yourdomain.com    5

The sender will try the first mail server (with priority 0). If mail.yourdomain.com rejects email by greylisting, then the sender would immediately try the second mail server (with priority 5).

Greylisting in Postscreen doesn’t have a delay time like in Postgrey. If the two mail server hostnames have the same IP address, then when the sender tries the second mail server hostname, the email will be accepted immediately (if all other checks pass) and end users will not notice email delay caused by greylisting.

Note that not all mail servers would immediately try the second MX host. Some mail servers like Gmail would use a different IP address to try again, which of course will be rejected again. Postfix would try the second MX host by default. I don’t know if it’s also the case with Exim. If you run Exim SMTP server, please comment below.

Skip Deep Protocol Tests If an SMTP Client’s IP Address is on a Public Whitelist

Gmail will never retry sending email from the same IP address. However, Gmail’s IP address is on list.dnswl.org. We can tell Postscreen to ignore such SMTP clients. Add the following line in the /etc/postfix/main.cf file to ignore clients whose score is equal to -2 or below.

postscreen_dnsbl_whitelist_threshold = -2

Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

The following message in my mail log indicates Postscreen didn’t perform deep protocol tests and passed the connection to smtpd daemon because Gmail’s IP address is on the public whitelist.

Feb 10 10:31:14 mail postfix/postscreen[16579]: CONNECT from [209.85.166.44]:38543 to [23.254.225.226]:25
Feb 10 10:31:14 mail postfix/dnsblog[16582]: addr 209.85.166.44 listed by domain list.dnswl.org as 127.0.5.0
Feb 10 10:31:15 mail postfix/postscreen[16579]: PASS NEW [209.85.166.44]:38543
Feb 10 10:31:15 mail postfix/smtpd[16639]: connect from mail-io1-f44.google.com[209.85.166.44]

As a matter of fact, most major mailbox providers (Gmail, Hotmail, Outlook, Yahoo Mail, GMX Mail, ProtonMail, etc) are whitelisted on list.dnswl.org. It also includes mail servers in other industries, as can be seen on dnswl.org.

  • 2 – Financial services
  • 3 – Email Service Providers
  • 4 – Organisations (both for-profit [ie companies] and non-profit)
  • 5 – Service/network providers
  • 6 – Personal/private servers
  • 7 – Travel/leisure industry
  • 8 – Public sector/governments
  • 9 – Media and Tech companies
  • 10 – some special cases
  • 11 – Education, academic
  • 12 – Healthcare
  • 13 – Manufacturing/Industrial
  • 14 – Retail/Wholesale/Services
  • 15 – Email Marketing Providers
  • 20 – Added through Self Service without specific category

So using postscreen_dnsbl_whitelist_threshold will help you skip greylisting most of the time.

Using Postwhite

Postwhite is a script written by Steve Jenkins to automatically generate a static IP whitelist for Postscreen by using the published SPF records of known webmailers, social networks, ecommerce providers, and compliant bulk senders. Note that this whitelist would make Postscreen skip all tests (pregreet test, public blacklist/whitelist check, deep protocol tests) for the whitelisted IP addresses, so it will help reduce the load on Postscreen and DNS requests to public blacklists/whitelists.

To use Postwhite, first cd to /usr/local/bin/.

cd /usr/local/bin/

Install git.

sudo apt install git

or

sudo dnf install git

Clone the SPF-Tools and Postwhite Github repository.

sudo git clone https://github.com/spf-tools/spf-tools.git
sudo git clone https://github.com/stevejenkins/postwhite.git

Copy the postwhite.conf file to /etc/.

sudo cp /usr/local/bin/postwhite/postwhite.conf /etc/

Run Postwhite.

sudo /usr/local/bin/postwhite/postwhite

postscreen whitelisting postwhite

The whitelist will be save as /etc/postfix/postscreen_spf_whitelist.cidr. Edit Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Find the following line.

postscreen_access_list = permit_mynetworks cidr:/etc/postfix/postscreen_access.cidr

Add the new whitelist file.

postscreen_access_list = permit_mynetworks cidr:/etc/postfix/postscreen_access.cidr cidr:/etc/postfix/postscreen_spf_whitelist.cidr

Save and close the file. Then restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Edit the root user’s crontab file.

sudo crontab -e

Add the following two lines at the end to regularly update the whitelist.

@daily /usr/local/bin/postwhite/postwhite > /dev/null 2>&1 #Update Postscreen Whitelists
@weekly /usr/local/bin/postwhite/scrape_yahoo > /dev/null 2>&1 #Update Yahoo! IPs for Postscreen Whitelists

Save and close the file. Now if you send an email from Gmail to your own domain email address, and check the mail log, you will find Postscreen doesn’t perform any tests, because the IP address is whitelisted.

Feb 10 13:04:17 mail postfix/postscreen[24895]: CONNECT from [209.85.166.44]:38257 to [23.254.225.226]:25
Feb 10 13:04:17 mail postfix/postscreen[24895]: WHITELISTED [209.85.166.44]:38257
Feb 10 13:04:17 mail postfix/smtpd[26596]: connect from mail-io1-f44.google.com[209.85.166.44]

Step 5: Analyze Postfix Logs

Pflogsumm is a great tool to create a summary of Postfix logs. Install it on Ubuntu with:

sudo apt install pflogsumm

On CentOS/RHEL, pflogsumm is provided by the postfix-perl-scripts package.

sudo dnf install postfix-perl-scripts

Use the following command to generate a report for today. (Note that on CentOS/RHEL, the mail log file is /var/log/maillog.)

sudo pflogsumm -d today /var/log/mail.log

Generate a report for yesterday.

sudo pflogsumm -d yesterday /var/log/mail.log

If you like to generate a report for this week.

sudo pflogsumm /var/log/mail.log

To emit “problem” reports (bounces, defers, warnings, rejects) before “normal” stats, use --problems-first flag.

sudo pflogsumm -d today /var/log/mail.log --problems-first

To append the email from address to each listing in the reject report, use --rej-add-from flag.

sudo pflogsumm -d today /var/log/mail.log --rej-add-from

To show the full reason in reject summaries, use --verbose-msg-detail flag.

sudo pflogsumm -d today /var/log/mail.log --rej-add-from --verbose-msg-detail

You can add a cron job to make pflogsumm to send a report to your email address every day.

sudo crontab -e

Add the following line, which will generate a report every day at 4:00 AM.

0 4 * * * /usr/sbin/pflogsumm -d yesterday /var/log/mail.log --problems-first --rej-add-from --verbose-msg-detail -q

To receive the report via email, add the following line above all cron jobs.

MAILTO="[email protected]"

You should pay attention to the message reject detail section, where you can see for what reason those emails are rejected and if there’s any false positives. Greylisting rejections are safe to ignore. The following screenshot indicates that the SMTP client failed Postscreen deep protocol tests.

postscreen deep protocol tests

Wrapping Up

I hope this tutorial helped you use Postscreen to block spambots. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 1 Average: 5]

One Response to “Enable and Configure Postscreen in Postfix to Block Spambots

  • Not bad for a girl. Joking aside. This is one of the most complete tutorials on the subject. Very well done.

    Tiny bit more info on postscreen_dnsbl_whitelist_threshold might be useful. I didn’t get why it doesn’t have its own _sites = at first.

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.