this presentation for the SNE Master Students at Innopolis University

  • low-level infrastructure services are critical

  • anti-spam methods

  • live acceptance testing of the some Postfix anti-spam features

Before we start

Everything clear about SMTP chains? What about smarthosts? (+ auth vs network?)

DNS and SMTP are so critical they are often outsourced

  • different kinds of sysadmins and IT profiles
  • explicit vs tacit knowledge
  • outsourced by IT outsourcing
  • outsourced by public Cloud-alike service
  • DIY for private use or your own IT company
  • smtp gateways (payable black-boxes vs DIY)
  • whatever you become (CTO or sysadmin), pressure is high e.g. inter-MX issues your fault or other's fault? (fast response)

MDA/MUA vs spambox vs smtp session

There are several ways to handle SPAM.

  • You can let the users deal with spam on their side e.g. using their own MDA/MUA e.g. Thunderbird Bayesian anti-spam feature.

  • You can filter it out from users' inboxes and let them review those in a dedicated spambox folder (for that they should use webmail or IMAP).

  • But the most effective way is to block the unsollicited messages directly during the SMTP session. This is what this PoC is about. We are going to proceed with an full acceptance testing of a DIY anti-spam gateway. With this method, the SPAM is refused by the Mail eXchanger and you are making users happy as long as there are not too much false-positives or inter-MX issues. Be ready to send Zircon missiles to other postmasters that sometimes do not understand anything about computing have no clue what an RFC is.

Those methods can be cumulated but one gets great results with filtering during the SMTP session already.

Message's source

Looking at a message's source:

  • return-path and delivered-to
  • SMTP chain (Received)
  • message headers
  • message body (how to say in russian?)

Layout of a standart SMTP session

Connect with telnet,

telnet 2525

Who you are (helo YOURSELF),


Who's email account are you impersonating (this is for the Return-Path)?

mail from:<>

Who are you wiling to send a message to?

rcpt to:root
rcpt to:<>

What are you willing to send (including the message headers)?

From: Me Me Me <>
To: Target <>
Subject: you have been spammed

spam content

Introduction about Acceptance Testing

  • What is acceptance testing?

==> Do not forget to make the customer sign it (even if some parts failed)!

  • Only Postfix (for now). Maybe with Exim soon.

(quick reminder of the major SMTP daemons available out there)


  • Note: This is not about infrastructures nor pre-sales considerations

One could consider distributing the postfix instances on different bare-metal or VMs or Docker containers against a shared storage. One could consider firewalling, load-balancing, CARP and DNS round-robin but this is out of topic. We are not reviewing infrastructure architecture for heavy production but only anti-spam specific tuning.

One could also consider the linkage between the SMTP services and the Calendar Webmail Chat etc. To undoom your customer or the company you will be working from from MS hosted mail facilities, the Open Source community does not have ideal answers yet. Microsoft is strong on the server market with their Exchange and Outlook products. Actually it is the only thing they got left. But I believe that we are going to take over this remaining peace too in the future (what else do they got anyway?).

By the way on the Desktop OS market, we (the Open Source community) are also becoming stronger with Unity, Cinnamon, MATE and Ubuntu Budgie.

Yes, given the labs you are working on, you are part of the community now.

Preparation -- Initial server setup

myorigin = $mydomain
#(default to FQDN minus the first component)
mydomain =
myhostname =
mydestination = $mydomain
mynetworks = [::ffff:]/104 [::1]/128

smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
delay_warning_time = 4h
readme_directory = no
compatibility_level = 2
alias_maps = hash:/etc/aliases

Forcing alias_maps because the default is alias_maps = hash:/etc/aliases, nis:mail.aliases.

Enabling delay_warning_time for user's convenience.

Changing port 25 to 2525 to workaround the blocked outgoing SMTP sessions from Innopolis networks as well as from Google Cloud (so we can also do some tests from those locations),

vi /etc/postfix/

#smtp      inet  n       -       y       -       -       smtpd
2525      inet  n       -       y       -       -       smtpd

Create a dummy mail user called user,

groupadd mailuser
useradd -g mailuser -m -s /sbin/nologin user

Preparation -- Initial client(s) setup

Check that you can reach out the target SMTPD from different locations/clients,


and that ports smtp and submission are not filtered,

nmap -p 25,587

Check that your own presence on the public network has a PTR and resolves,

curl -s | egrep '^your ip|resolves'

Setup Expect and Autoexpect to automate telnet test sessions for this PoC acceptance testing,

apt install expect expect-dev

Re-do the sample SMTP session with Expect,


Acceptance Testing with default relay restrictions (negative control)

  • What happens if there is no HELO/EHLO?
  • What happens if there is no MAIL FROM?
  • What destination domain(s) is the basic setup receiving?
  • What happens if you want to send to another domain?




  • So what is an Open Relay?
  • Are there other kinds of Open Relays? (meaning non-SMTP)
  • Are there SMTPs that are not relays?
  • What about an MX?
  • Do the Received fields in the message source tell us everything about message's path?
  • Why do end-users almost never see the Relay Access Denied error?
  • Is it normal the basic-pass script passes through?
  • Should we keep the default configuration as-is?

Hint on # RELAY restrictions

Most important importantly (here used config = default),

#smtpd_relay_restrictions (default: permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination)
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

Acceptance Testing # NETWORK restrictions (smtpd_client_restrictions)

Beware of the Postfix version. The syntax is continuously changing esp. between versions 2.x and 3.x. Do NOT copy/paste configuration snippets from the web. Read The Freacking Manual man 5 postconf and Postfix Documentation. How to find relevant manual pages by the way?

The tested configurations are enabled then disabled so the next one can actually be tested (it also helps to get back to the scientific negative control status anyway).


tail -F /var/log/mail*

and for production progressively seperate the output, at least look at both logs separately,

tail -F /var/log/mail.log
tail -F /var/log/mail.err

Note: On Redhat systems there is /var/log/maillog.

enabling in,



from an NXDOMAIN client

450 4.7.1 Client host rejected: cannot find your reverse hostname, []
450     Requested mail action not taken: mailbox unavailable

replacing with,



unknown_client_reject_code   = 554


from an NXDOMAIN client

554 5.7.25 Client host rejected: cannot find your hostname, []
554     Transaction failed

Note: the client IP has changed in the meamwhile. This has nothing to do with the Schmilblick.


example on production system


# this is too restrictive
#   reject_rhsbl_sender,

# apews is blocking (
#   reject_rbl_client,

# not found
#   reject_rbl_client,


example on prod server

Sep 14 10:05:37 postfixprod postfix/smtpd[18751]: NOQUEUE: reject: RCPT from[]:50029: 554 5.7.1 Service unavailable; Client host [] blocked using; Blocked - see; from=<> to=<> proto=ESMTP helo=<>

Sep 10 01:47:37 postfixprod postfix/smtpd[9923]: NOQUEUE: reject: RCPT from[]:31497: 554 5.7.1 Service unavailable; Client host [] blocked using; Blocked - see; from=<> to=<> proto=ESMTP helo=<>

Sep 13 14:21:18 postfixprod postfix/smtpd[17080]: NOQUEUE: reject: RCPT from[]:37099: 554 5.7.1 Service unavailable; Client host [] blocked using; Client host blocked using Barracuda Reputation, see; from=<> to=<> proto=ESMTP helo=<>

Aug 11 05:49:19 postfixprod postfix/smtpd[19570]: NOQUEUE: reject: RCPT from[]:58944: 554 5.7.1 Service unavailable; Client host [] blocked using;; from=<> to=<> proto=ESMTP helo=<>

Note: IAP's IP address ranges are blocked! What does this mean for SMTP servers at home?



telnet bulk,

from any client

(echo helo crap; echo mail from:whatever; echo rcpt | telnet 2525

returns (instead of Relay Access Denied),

Client host rejected: Improper use of SMTP command pipelining

enabling SPF policy,

on aws

less /etc/nsd/

on hosted NS with WEB GUI

and testing,

from a system that can do outgoing tcp/25,

telnet 25

(could not reproduce -- TXT record broken?)

usually returns,

on production system

Sep 14 15:28:38 postfixprod postfix/smtpd[19305]: NOQUEUE: reject: RCPT from unknown[]:44712: 550 5.7.1 <unknown[]:44712>: Client host rejected: Message rejected due to: SPF fail - not authorized. Please see;;ip=;; from=<> to=<> proto=ESMTP helo=<>

enabling client_access,

on production system

vi /etc/postfix/client_access
postmap /etc/postfix/client_access
ls -lhF /etc/postfix/client_access


from a system that can do outgoing tcp/25,

telnet 25


554 5.7.1 <[]:47566>: Client host rejected: is identified as a spam domain

Acceptance Testing # HELO/EHLO restrictions


smtpd_helo_restrictions = permit_mynetworks,

#reject_unknown_helo_hostname --> unknown_hostname_reject_code
unknown_hostname_reject_code = 554

gives among others,

554 5.7.1 <>: Helo command rejected: Host not found

Acceptance Testing # MAIL FROM restrictions

#postmap /etc/postfix/sender_access
smtpd_sender_restrictions = permit_mynetworks,
    check_sender_access hash:/etc/postfix/sender_access,

#        warn_if_reject,
#too restrictive, this prevents unreal addresses to send
#you messages.  try to book a hotel or a flight with that
#and you will feel the pain,
#       reject_unverified_sender
#unverified_sender_reject_code = 550
#unverified_sender_reject_reason = Address verification failed
#address_verify_map = proxy:btree:$data_directory/verify_cache
#address_verify_cache_cleanup_interval = 72h
# Postfix 2.6 and later.
# unverified_sender_defer_code = 250
#proxy_write_maps = $smtp_sasl_auth_cache_name $lmtp_sasl_auth_cache_name $address_verify_map $postscreen_cache_map

Acceptance Testing # RCPT TO restrictions

smtpd_recipient_restrictions = permit_mynetworks,

#reject_unknown_sender_domain --> unknown_address_reject_code
#reject_unknown_recipient_domain --> unknown_address_reject_code
unknown_address_reject_code  = 554

# DATA restrictions
# Block clients that speak too early.
smtpd_data_restrictions = reject_unauth_pipelining


Further readings