Postfix Spam Filter using Ubuntu Dapper, MailScanner, SpamAssassin, Razor, Pyzor, DCC and ClamAV - Page 3

2.3 Postfix Anti-Spam Settings

Preliminary Notes:

When a client (a computer trying to send us mail) connects to Postfix and begins a communication session, Postfix records information about that session. Prior to the point where Postfix accepts mail from that session for delivery, we have the option of evaluating the session and rejecting the mail by setting some restrictions in This link illustrates what happens during a typical SMTP session: The restrictions below help ward off some spam and prevent our system from becoming an open relay. These restrictions cause some mail to be rejected by Postfix right at the "front door". This will save system resources because the mail will not enter our system and therefore will not be scanned by MailScanner (and subsequently by SpamAssassin). This is good and bad. It saves system resources, but it also doesn't let you see the rejected mail. All you will see is a log entry or two from Postfix saying essentially "Hey, a mail server named "xxxxxxxx" at IP address X.X.X.X tried to send some mail in, but it broke rule XYZ, so I rejected it". Now this could have been spam (spammers often intentionally don't follow RFCs in order to accomplish their goals) but if it was a "legitimate" mail, say from a customer whose IT Department has simply misconfigured their mail server (it happens), you could have some ruffled feathers to deal with.

If you want to allow ALL mail addressed to us to come in the front door, and therefore allow MailScanner/SpamAssassin to handle all spam control within the system, you would need to modify a couple of the settings below. I personally find a combination of Postfix and SpamAassassin anti-spam control to be best. At the very least you need to insure you do not disable the built in default anti-relay control in Postfix (smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination).

The configuration below is actually very conservative, allowing most email to come in the front door so MailScanner and SpamAssassin have their shot at it. For me it (safely) rejects about 35% of the email bound for my users, so I think these settings are quite valuable. I recommend this approach to start. Adding additional restrictions will increase the likelihood of rejecting valid email from improperly configured computers. If you decide to add/remove permissions/restrictions in the future, do so one at a time and give yourself ample time to evaluate the effect of the change. I strongly suggest you actually have a good understanding of how these restrictions work before you make changes to the entries below. Among other things, getting this stuff wrong could reject legitimate mail and/or cause us to become an open relay. Note that restrictions don't always restrict, some also permit.

If you want to gain a better understanding of these settings, good resources are,,, the somewhat dated (2001), and this excellent book. You will note I only use a couple of the same settings as these, so this configuration is no where near as restrictive. Keep in mind that SpamAssassin and MailScanner will come into the picture in a bit, and will provide us with much more flexible and configurable options to recognize and manipulate spam.

2.3.1 smtpd_helo_required

Make any connecting mail server do a proper smtp "handshake" and announce its name. Internet RFCs require this, so we do too.

postconf -e "smtpd_helo_required = yes"

Preface: Postfix' restriction stages are as follows, and are processed in the following order:


We are only going to place entries in the last three restriction stages. Restriction stages are processed in this order regardless of the order listed in

2.3.2 smtpd_sender_restrictions

This restriction stage restricts what sender addresses this system accepts in MAIL FROM: commands (the envelope sender). We will place three tests (restrictions) in this restriction stage.

A restriction stage holds a list of restrictions (tests). Typically, tests evaluate to either DUNNO, REJECT, or OK. DUNNO means "I don't know what to do, let the next test decide". REJECT simply rejects the mail. OK means no more tests are performed in this restriction stage, tests continue with the next stage (if any). Reject_* type tests typically evaluate to REJECT or DUNNO. Permit_* type tests typically evaluate to OK or DUNNO, and check_*_access type tests can perform a variety of actions. The illustration shows the basic logic.

         SMTP session
restriction stage-------------
  test ---------------REJECT->
  |   \
  |    DUNNO
  |     \
  |      V
  |   next test------REJECT->
  |      |   \
  OK     OK   DUNNO
  |      |     \
  |      |      V
  V      V
  next restriction stage-------> check_sender_access

See Here we ask Postfix to compare the envelope sender to entries in an /etc/postfix/sender_access database and act upon those entries if a match is found. We also define what action is taken there (OK, DUNNO, REJECT etc.) on a sender by sender basis. If the sender is not listed in the file, the test evaluates to DUNNO, and the next test is performed. I will provide examples a little later. One use of this file is to place a list of senders (email addresses, domains, network addresses etc.) from which we wish to not receive mail (blacklist them). We will also have the ability to blacklist senders in MailScanner and SpamAssassin but it will save resources if we blacklist them here. We will also use this file to allow specific senders to bypass the next two tests in this restriction stage. If we give them an OK here, no more tests are performed in this restriction stage, the tests continue in the next restriction stage (smtpd_recipient_restrictions). Note that if we were to place this setting in the smtpd_recipient_restrictions restriction stage before the reject_unauth_destination test, and we were to give someone the OK there, the reject_unauth_destination test located there would be bypassed. This would be bad because anyone we gave the OK to would then be able to use our server as an open relay. Access restrictions are evaluated in the same order we list them, and if a match is found it will influence how (whether) further restrictions are evaluated. reject_non_fqdn_sender

Reject when the envelope sender mail address is not in the proper format. Remember, the "envelope sender" is what the sending mail server gives in the "MAIL FROM:" line during the SMTP session, not the header "From:" line. "Joe" is not allowed to send us mail (because we can't reply to "Joe") but "[email protected]" is at the very least an email address. If the sender does not get rejected at this point, this test evaluates to "DUNNO". reject_unknown_sender_domain

Reject when the envelope sender's domain part of the mail address has no DNS "A" or "MX" record at all. This setting kicks about 35% of the mail coming in my mail server. It is common for spammers to use a bogus domain name so they don't have to deal with the backlash of rejected mail. It is also important for us not to fill up our queue with Bounce notices that can never be delivered due to the fact that the sender's domain does not even exist. If the sender's domain has an "A" or "MX" record, this test will also evaluate to "DUNNO". On occasion, you will see in a report that someone you wish to receive mail from has been rejected by this setting. One possible cause of this is when legitimate senders deliberately use bogus domain names so you will not reply to them. This is where the sender access list comes in handy. You can give them an OK there, and this test will be bypassed.

Now to implement these three restrictions:

postconf -e "smtpd_sender_restrictions = check_sender_access hash:/etc/postfix/sender_access, reject_non_fqdn_sender, reject_unknown_sender_domain"

2.3.3 smtpd_recipient_restrictions

The access restrictions that the Postfix SMTP server applies in the context of the RCPT TO: command. This refers to the "envelope recipient" which is what the client gave in the "RCPT TO:" line during the SMTP session, not the header "To:" line. smtpd_recipient_restrictions is another restriction stage that holds a list of specific restrictions. Other restriction stages that are evaluated prior to smtpd_recipient_restrictions are smtpd_client_restrictions, smtpd_helo_restrictions and smtpd_sender_restrictions (in that order). Restrictions that would normally go in these prior restriction stages can alternately be placed in smtpd_recipient_restrictions. Therefore, some people prefer to place all the smtpd_*_restrictions that would normally go in prior restriction stages into smtpd_recipient_restrictions (in the proper order) and leave the prior stages unconfigured (empty). In our case it is safer to use smtpd_sender_restrictions and smtpd_recipient_restrictions. Let's look at those specific restrictions (tests) we place in smtpd_recipient_restrictions: permit_mynetworks

Allows machines listed in "mynetworks" to skip the rest of the tests in this restriction stage (permit = OK). In other words, it exits this stage and is tested in the next stage (smtpd_data_restrictions). Because permit_mynetworks is placed in front of reject_unauth_destination, this means machines in $mynetworks are allowed to relay mail to any domain. Without this, we would only be able to send mail to our own domain(s). If the IP address of the sender is not listed in $mynetworks, the test evaluates to "DUNNO" and continues on to the next test (reject_unauth_destination). reject_unauth_destination

This, along with permit_mynetworks is used for relay control. This setting, in essence, means that mail bound for any domain that we have not configured our machine to accept mail for will be rejected. In our case Postfix will use the relay_domains setting (or table) that we configured earlier to determine what domains those are. See for additional details. If the domain is listed in relay_domains, this test evaluates to "DUNNO" and the session is allowed to go on to the next test (if any). Just like "mynetworks", this setting is extremely critical. By placing permit_mynetworks directly ahead of reject_unauth_destination, we are assured that we can send mail to domains other than ours, but we will only accept mail addressed to us from computers outside our network, thus permit_mynetworks and reject_unauth_destination work as a team. reject_unauth_pipelining

Rejects bulk mailers that attempt to use pipelining to speed delivery, without checking if it is supported first (non-RFC, common among spammers).

Now to implement these three restrictions:

postconf -e "smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, reject_unauth_pipelining"

2.3.4 smtpd_data_restrictions

Optional access restrictions that the Postfix SMTP server applies in the context of the SMTP DATA: command. Like smtpd_recipient_restrictions, this is a restriction stage. reject_unauth_pipelining

I repeat this setting in smtpd_data_restrictions as it is not always effective when placed in smtpd_recipient_restrictions. I include it in smtpd_recipient_restrictions as I like to place it prior to any policy servers. Note that there are only a couple of restrictions that make good use of smtpd_data_restrictions.

postconf -e "smtpd_data_restrictions = reject_unauth_pipelining"

2.3.5 Postfix content filtering control files: - /etc/postfix/header_checks and /etc/postfix/body_checks

These files will list certain "strings" of text, and tell Postfix what to do with mail if it encounters these strings in email headers or the body of the message. Sample files are already created for us, with comments explaining what to put in them. You can edit them at your leisure. Note that these files require the use of "regular expression format". "regexp" is something you'll want to learn about in order to live in the *nix world. Get a book or research it on the Net sometime. For an example of an elaborate header_checks file from someone with an attitude, take a look at But don't blindly follow this, it's only an example! Here is an example of a body_checks file: It would be worth your while to check out when you have a leisure moment. Specifically and I recommend against making a large number of changes to any part of Postfix without giving yourself plenty of time to evaluate the effects. Like a turtle, go slow, live long. header_checks & body_checks

Let's go ahead and put these two in header_checks is required because it allows us to hold all incoming email in order for MailScanner to do it's thing:

postconf -e "header_checks = pcre:/etc/postfix/header_checks"

postconf -e "body_checks = pcre:/etc/postfix/body_checks"

Edit header_checks:

vi /etc/postfix/header_checks

Add this line to the header_checks file, without it MailScanner will not work:

/^Received:/ HOLD

Note that we do not have to postmap pcre type tables. They remain plain text and Postfix uses them "as is".

You could also configure mime_header_checks and nested_header_checks along with header_checks and body_checks. If you get too creative with content filtering in Postfix (using header_checks and body_checks), it can have a significant impact on performance. /etc/postfix/sender_access

We referenced this file in smtpd_sender_restrictions. We use this file to check the sender right at the front door. In this file, we'll list certain senders/domains/IPaddress ranges for special handling. Below are bogus examples, create your own as you see fit. Please read /etc/postfix/sender_access for more information. Although you could use this file for various purposes, considering the way we have set this up in smtpd_sender_restrictions, I suggest using it to either blacklist senders, or allow certain senders to bypass the remaining tests in smtpd_sender_restrictions.

vi /etc/postfix/sender_access
#Example sender access map file
[email protected] 550 No MLM thanks
allspam.tld 550 Spam is not accepted here REJECT
[email protected] REJECT OK OK

Since this is a hash table, you need to postmap it as usual:

postmap /etc/postfix/sender_access

2.3.6 Final Look at the Postfix Install

Riview changes:

less /etc/postfix/

Check the contents of the file for errors and repair if needed. Fire up Postfix:

postfix start

Check that Postfix responds:

telnet 25

You should see:

220 [yourFQDNhere] ESMTP Postfix (Ubuntu)

hit [enter] a few times; then type quit to exit.

If it does not reply in this manner, open another terminal window and stop Postfix postfix stop. Make sure you ran newaliases and all the postmap commands above. Check all the settings in and There is a nice paper on troubleshooting Postfix at but keep in mind our system is not ready to relay mail at this point (it will end up in the queue).

Any time you make changes to or or to data tables, most (not all) of the time, it is required that you to reload Postfix with:

postfix reload

Now that we have a basic Postfix configuration, and are good places to gain a better understanding of some of the settings we used and at this point these READMEs will make more sense.

By default, our Postfix runs chrooted. If you don't know what that means, it will not matter much at this point. I leave it to you to research what chroot means at some later time. Some of the system files that Postfix needs to run properly were copied to Postfix's chroot jail (/var/spool/postfix) during installation. On occasion, the original files will get modified, and Postfix will complain that the copy it has is not the same as the original. When this happens, you can manually copy the file(s) postfix has complained about to the chroot jail, or we can simply run a script that is supplied with the Postfix source code (called LINUX2) that will once again copy all the files that Postfix needs to where it needs them.

cd /usr/local/src/postfix-2.3.3/examples/chroot-setup
postfix start
chmod +x LINUX2
cp LINUX2 /usr/bin
postfix check

This makes the LINUX2 script executable, copies it to a directory in our path, then executes it. LINUX2 will usually resolve any issues or problems with Postfix if you see any errors in the logs with Postfix accessing configuration files or directories.

Share this page:

Suggested articles

2 Comment(s)

Add comment


By: Anonymous


postfix start


/etc/init.d/postfix start ?

By: fdalmoro

just 'postfix start' works fine too without having to put in the /etc/init.d/postfix in it.