Postfix Training

Basic MTA Configuration

All instructions here are for Postfix. If you want to use a different MTA then you will mostly be working without instructions.

  1. To install Postfix run “apt install postfix” (or for the preconfigured images I setup reconfigure it by running “rm /etc/postfix/ ; dpkg-reconfigure postfix“.
    1. Select “Internet Site” for the type of mail configuration.
    2. Enter the domain name you selected for the mail name (for the VMs I host it will be
    3. When it asks for a user to receive root mail set it to the name of a test user (EG “test”). Make the user with the command “useradd -m test
    4. When it asks for a comma separated list of domains delete the default text for that field and replace it with
    5. For “Force synchronous updates on mail queue” select No as apparently modern filesystems don’t need it and it significantly increases system load. If you say Yes this causes shell code equivalent to the following to be run:
      cd /var/spool/postfix
      chattr +S incoming active bounce defer deferred flush saved corrupt
    6. For “local networks” and the other settings the defaults should be good.
    7. After running the Debian package configuration create the account you specified for the root email, if it was “test” then run “useradd -m test“.
  2. The main Postfix configuration file is /etc/postfix/ Change the myhostname setting to the fully qualified name of the system, something like
    You can edit /etc/postfix/ with vi (or any other editor) or use the postconf command to change it, eg “postconf -e“.
  3. Add “home_mailbox=Maildir/” to the Postfix configuration to make it deliver to a Maildir spool in the user’s home directory (the trailing / is important).
  4. Restart Postfix to apply the changes.
  5. Test delivery by installing swaks via “apt install swaks libio-socket-inet6-perl” and then running the command “swaks -f -t -s localhost“. Note that swaks displays the SMTP data so you can see exactly what happens and if something goes wrong you will see everything about the error.
  6. Inspect /var/log/mail.log to see the messages about the delivery. View the message which is in ~test/Maildir/new.
  7. When other students get to this stage run the same swaks command but with the -t changed to the address in their domain, check the mail.log to see that the messages were transferred and view the mail with less to see the received lines.

Certbot Configuration

To avoid password sniffing we need to use SSL for both authenticated sending of mail and for receiving mail via POP/IMAP.

Run the following commands to install letsencrypt (also the gnutls-bin utilities to test SSL and the libnet-ssleay-perl library for swaks with SSL support) and request a SSL certificate:

apt install certbot gnutls-bin libnet-ssleay-perl
letsencrypt certonly --standalone -m $EMAIL_ADDRESS -d

Run the command “gnutls-cli --starttls-proto=smtp” to check the certificate used by Postfix, it should say that the certificate is not trusted.

Run the following commands to change the Postfix configuration to use the TLS certificate and then repeat the gnutls-cli command to show that it works:

postconf -e smtpd_tls_cert_file=/etc/letsencrypt/live/
postconf -e smtpd_tls_key_file=/etc/letsencrypt/live/
postconf -e smtpd_tls_CAfile=/etc/letsencrypt/live/
postconf -e smtpd_tls_received_header=yes
postconf -e smtpd_tls_loglevel=1
systemctl restart postfix.service

To test the SMTP TLS the command go to another system and run “swaks -f -t -s -tls -tlsp tlsv1_3“, this specifies that the connection must be encrypted via TLS version 1.3 (the most secure SSL protocol).

Basic Pop/IMAP Configuration

All instructions here are for Dovecot. Other POP/IMAP servers are available, but there is less reason for choosing an alternative than there is for the MTA.

  1. Run “apt install dovecot-pop3d dovecot-imapd” to install Dovecot POP and IMAP servers.
    Run “netstat -tln” to see the ports that have daemons listening on them, observe that ports 110, 143, 993, and 995 are in use.
  2. Edit /etc/dovecot/conf.d/10-mail.conf and change “mail_location = mbox:~/mail:INBOX=/var/mail/%u” to “mail_location = maildir:~/Maildir“. Then restart Dovecot.
  3. Run the command “nc localhost 110” to connect to POP, then run the following commands to get capabilities, login, and retrieve mail:
    user test
    retr 1
  4. Run the command “nc localhost 143” to connect to IMAP, then run the following commands to list capabilities, login, and logout:
    a capability
    b login test WHATEVERYOUMADEIT
    c logout
  5. For the above commands make note of the capabilities, we will refer to that later.

Now you have a basically functional mail server on the Internet!


Edit /etc/dovecot/conf.d/10-ssl.conf, remove the following 2 lines:

ssl_cert = </etc/dovecot/private/dovecot.pem
ssl_key = </etc/dovecot/private/dovecot.key

Add the following 2 lines:

ssl_cert =</etc/letsencrypt/live/
ssl_key = </etc/letsencrypt/live/

Restart Dovecot, then run the command “gnutls-cli” to connect via encrypted POP and after the connection is established you can use the same POP commands as before.


SASL is the system of SMTP authentication for mail relaying. It is needed to permit devices without fixed IP addresses to send mail through a server.

Run the following commands to configure Postfix for SASL:

# allow parts of Postfix to work with the same configuration regardless of whether they are running in a chroot
mkdir -p /var/spool/postfix/var/spool
ln -s ../.. /var/spool/postfix/var/spool/postfix
# configure Postfix for SASL with Dovecot as authentication server
postconf -e smtpd_sasl_auth_enable=yes
postconf -e smtpd_sasl_type=dovecot
postconf -e smtpd_sasl_path=/var/spool/postfix/private/auth
postconf -e broken_sasl_auth_clients=yes
postconf -e smtpd_sasl_authenticated_header=yes
systemctl restart postfix.service

Edit /etc/dovecot/conf.d/10-master.conf, uncomment the following lines, and then restart Dovecot:

unix_listener /var/spool/postfix/private/auth {
 mode = 0666

Edit /etc/postfix/, uncomment the line for the submission service, and restart Postfix. This makes Postfix listen on port 587 which is allowed through firewalls.

From another system (IE not the virtual machine you are working on) run “swaks -f -t YOURADDRESS -s -tls -tlsp tlsv1_3” (where YOURADDRESS is an address you use) and note that the message is rejected with “Relay access denied“.

Now run “swaks -f -t YOURADDRESS -s -tls -tlsp tlsv1_3 --auth-user test --auth-password WHATEVER and note that the message is accepted and observe that the mail is delivered (subject to anti-spam measures at the recipient).

Configuring a MUA

If every part of the previous 3 sections is complete then you should be able to setup your favourite MUA. Use “test” as the user-name for SMTP and IMAP, for the SMTP/IMAP server and it should just work!

Note that as the VMs I run are only accessible by SMTP and IMAP over IPv6 you need to have IPv6 on your workstation to connect. If you don’t have IPv6 then run a text mode MUA such as mutt on the VM.

Anti Spam

  1. Header checks allows rejecting mail based on known bad headers (such as blocking known spammers.
    1. Run the following command to send a test message (should work):
      swaks -f -t -s localhost
    2. Create the file /etc/postfix/header_checks with the following contents:
      /^From:.* REJECT

      This consists of a regular expression matching a header line and a policy (generally only REJECT makes sense).

    3. Run the following commands to enable it:
      postconf -e header_checks=regexp:/etc/postfix/header_checks
      systemctl restart postfix.service
    4. Test it with the following swaks command that should be rejected:
      swaks -f -t -s localhost
    1. Run the following command to install the postfix-policyd-spf-python package, this is a daemon that is launched by the Postfix master process for the use of other Postfix processes:
      apt install postfix-policyd-spf-python
    2. Add the following line to /etc/postfix/
      policyd-spf  unix  -       n       n       -       0       spawn user=policyd-spf argv=/usr/bin/policyd-spf
    3. Run the following command to set the smtpd_recipient_restrictions (which hasn’t been set previously in this exercise):
      postconf -e smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,check_policy_service unix:private/policyd-spf,reject_unauth_destination
    4. Then restart postfix and SPF checks will be enabled.
    1. Run the following command to install SpamAssassin packages:
      apt install spamassassin spamc spamass-milter
    2. Configure Postfix to use SpamAssassin as a milter (a mail filter program supporting the Milter interface from Sendmail):
      postconf -e smtpd_milters=unix:/var/spool/postfix/spamass/spamass.sock
    3. Edit /etc/default/spamass-milter and set the following as the OPTIONS line:
      OPTIONS="-u spamass-milter -i -r 5 -- -s 100485760"

      This sets a SpamAssassin score of 5 be the criteria for rejecting mail (the default for the SpamAssassin spamd daemon, spamass-milter should match spamd in this regard) and sets 10MB as the amount of data to be scanned in a message (the default is that mail that isn’t small bypasses some tests, the -s option is passed to spamc the SpamAssassin utility that talks to the daemon. Note that any typo in this line will cause things to break in unexpected ways that are difficult to debug.

    4. Run the following commands to restart all daemons and then test sending mail:
      systemctl restart spamassassin.service
      systemctl restart spamass-milter.service
      systemctl restart postfix.service
    5. Get the GTUBE spam test and try sending it to verify that spam mail is rejected:
      apt install wget
      cd /tmp
      swaks -f -t -s --body /tmp/gtube.txt

      This message should be rejected because GTUBE is a standard pattern for testing anti-spam systems.

    1. Run the following command to install DKIM packages:
      apt install opendkim opendkim-tools

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>