I assume I don’t have to introduce the concept of spam. Fighting spam can be done on different levels. A first line of defense is the mail server receiving them. There are several checks it can perform. Here is my configuration of Postfix.

I chose to leave smtpd_client_restrictions, smtpd_helo_restrictions and smtpd_sender_restrictions blank and do all the checks in smtpd_recipient_restrictions. While it’s possible to reject messages earlier, this setup gives more info in the logs for rejected messages.

Edit: Be careful with this! By pushing all restrictions under a single parameter, the order of the filters become very important! Make sure you understand the warnings described in the postfix manual.

These are the filters that I apply.

First, the local originated mail is allowed:

  • permit_mynetworks: Allow local originated mail

Mail servers introduce themselves with their hostname. RFC 5321 requires that all hostnames are fully qualified.

  • reject_non_fqdn_hostname: Non fully qualified hostnames names are rejected.
  • reject_invalid_hostname: Hostnames which have an invalid syntax are rejected as well.

The next phase in the SMTP conversation is identifying the sender. SMTP has an “envelope sender”. This is the address where bounces are returned to. Usually, this is the same as the “From” field, but this is not required. If my mailserver is to accept responsibility to deliver the mail, it should have a way to contact the sender. If the sender address is not usable, we can’t bounce if needed. Don’t accept responsibility in this case.

  • reject_non_fqdn_sender
  • reject_unknown_sender_domain

The same applies for the recipients:

  • reject_non_fqdn_recipient
  • reject_unknown_recipient_domain

The next statement is very important: don’t become an open relay. Only accept mail for the domains you’re actually responsible for:

  • reject_unauth_destination

The previous tests were local and fast. The mail-server can verify them with minimal effort. But this is not enough to fight spam. Greylisting in particular is very effective. Greylisting will cause every mail to be initially rejected with a temporary failure. RFC 5321 requires sending mail-servers to retry this delivery. On a second attempt, the message is accepted.

  • check_policy_service inet: The greylisting server listens on this port and keeps the database of seen mails

SPF is another anti-spam technique. This verifies that the sending mail-server is actually allowed to send mail from this email-address. However, this causes problems with standard forwarding of emails, so I don’t use it to reject messages, but I do log the result

  • warn_if_reject, check_policy_service unix:private/policy-spf

As a final test, several blacklists are checked. If the sending mail-server is listed as a known spammer, the mail is rejected.

  • reject_rbl_client bl.spamcop.net
  • reject_rbl_client sbl-xbl.spamhaus.org
  • reject_rbl_client dnsbl.sorbs.net

All previous configuration will either accept the mail for delivery, or reject the mail. It will not silently drop mail, which is a very important thing in my opinion. If you really want to, you can chain spamassassin to the end.


  1. Chris says:

    Are you able to post your main.cf as I tried your suggestion and it went to custard, trying to work out where I went wrong…

  2. Niobos says:

    Here is the relevant part:

    # Restrictions during SMTP commands (in order)
    smtpd_client_restrictions =
    smtpd_helo_restrictions = 
    smtpd_sender_restrictions = 
    # some checks can already be performed in the above stages.
    # Running them below allows us to gather more information on the mail before
    # rejecting it.
    # 10023 is the greylist server
    smtpd_recipient_restrictions = permit_mynetworks,
    	check_policy_service inet:,
    	warn_if_reject, check_policy_service unix:private/policy-spf,
    	check_recipient_access hash:/etc/postfix/spamassassin
    	reject_rbl_client bl.spamcop.net,
            reject_rbl_client sbl-xbl.spamhaus.org,
            reject_rbl_client dnsbl.sorbs.net
    spf-policyd_time_limit = 3600
    # Restrictions during SMTP DATA
    #header_checks = regexp:/etc/postfix/header_checks
    header_checks = 
    body_checks = 
  3. Aquel says:

    According to the postfix documentation, it is dangerous to rely on the recipient restrictions only:
    In your particular case, your configuration seems alright but for other people their too-permissive restrictive could lead to an unprotected mail server.

  4. Niobos says:

    Thanks Aquel,
    I’ve added a paragraph in the post to warn readers that don’t come down to the comments section.