User Tools

This is an old revision of the document!


Configuration: postfix

Postfix is the Mail Transfer Agent, the tool that actually moves your email messages from a the sender to the destination (recipient). It speak the Simple Mail Transport Protocol (SMTP) and it has some serious responsibilities which are:

  • Ensure that mail for you is properly delivered to you
  • Ensure that mail from you is properly sent to whoever need to deliver it
  • Filter out all undesired mail (spam)
  • Prevent abuse from malicious actors who pretend to be you to send unauthorized mail in your name
  • Prevent abuse from spammers to send mail pretending to be others (not act as an open relay)
  • Ensure that all good practices are followed to prevent your mail server from being listed in blacklists and flagged down as a spammer.

Due to these many tasks, an MTA is not a simple piece of software to properly setup. Postfix is no exception, and you need to understand a few basic concepts before proceeding.

Mail Delivery Pipeline

Traditionally, on UNIX systems, a mail server would deliver and send e-mails for local users as defined in the /etc/passwd file of the server itself. This is called local delivery and it is linked to the concept of mynetwork. In our modern internet world, this has substantially changed.

Nowadays you have a complete separation between server users and email accounts. But the traditional approach needs to be considered when configuring Postfix.

The pipeline is:

  • An SMTP client connect to your Postfix (SMTP server)
  • Optional TLS encryption is performed
  • The client identifies itself (HELO / EHLO)
  • Optional authentication is performed using SASL
  • Sender identifies itself (MAIL FROM:)
  • Recipient is identified (RCPT TO:)
  • Email data is transferred (DATA…)

Along all the steps of this pipeline, Postfix can be configured to perform checks to reject the entire transaction.

The local delivery

Emails will be delivered locally to local users on the server. I mean, users of the server, like users that can login on the server via shell and such. In the local delivery concept, there is no difference between user and mailbox.

In our case, local delivery will be routed to virtual delivery, no local server users will be able to receive emails.

The virtual delivery

Emails will be delivered to a list of domains and mailboxes, not users. It's called virtual because there the domains and the mailboxes are defined in a database and are not linked to real users of the server.

For our needs, i will show you how to link PostfixAdmin SQLite database to Postfix to perform domains and mailboxes lookup. Postfix virtual delivery activity will be deferred to Dovecot LMTP (Local Mail Transport) so that the emails are properly stored in to Dovecot management.

The mail Relay

So far, i always referred to emails to be delivered to the server (local) or to domains hosted on the server (virtual). What about emails to be delivered to others? This is called email relay and it happens when the Postfix server accepts an email destination which is not local, nor virtual.

The relay should be allowed only to authorized users to prevent spammers to abuse our server, which will cause the server itself to be blacklisted and unable to send any emails at all.

Mail Security

The SMTP protocol by itself is unencrypted and unsecure. This was maybe ok at the beginning of Internet, but not today. Today you need to enable both authentication and encryption.

Encryption is performed using TLS, but for legacy reasons you cannot require it. There are three types of SMTP connections:

  • Plain, no TLS (port 25)
  • STARTTLS, connection starts unencrypted and can be upgraded to a TLS connection if both parties support it
  • SSL/TLS, connection must be extablished encrypted (port 587)

Plain must always be provided, but you can at least prohibit authentication on non-encrypted connections.

The https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer~SASL (Simple Authentication Security Layer) is used for authentication. This implies the trnasmission on the connection of the username+password combination using a Base64 encoding. Please note, and this is very important, that Base64 is not an encryption and can easily be de-coded. For this reason, it is mandatory that authentication is enabled only is TLS too is enabled.

Postfix does not provide a SASL authenticator, this is demanded to Dovecot SASL implementation. The added value of this choice is to have the same background for both SMTP and IMAP servers.

Postfix documentation resources

Postfix website has tons of great documentation, which i strongly suggest you go read. Basic configuration, Virtual delivery, SASL, TLS.

On the internet there are lots of wikis and HOWTOs about postfix, including this page specific to Gentoo. Most of them are outdated or mix different approaches, i strongly suggest to go to the source and read the Postfix links above instead.

Postfix Configuration

Postfix configuration files are located under /etc/postfix and can be summarized as:

  • main.cf: contains all the oeprative directives of Postfix
  • master.cf: contains the services started by Postfix
  • sql/*.cf: the specific SQLite link files. You need to create this folder.

Please note that Postfix configuration is deeply connected to Dovecot, Spamassassin, SPF, OpenDKIM and OpenDMARC. The following configuration assumes you have already configured them all. So before you start Postfix you will need to set them up as well. See the relevant pages.

Postfix support all kinds of SQL databases, including SQLite. To integrate it, you need to create a few cf files and specify associated directives in the main.cf.

Create the sql folder:

mkdir /etc/postfix/sql

Drop all the following files in the sql folder.

File: /etc/postfix/sql/virtual_mailbox_domains.cf which fetch the list of domains:

virtual_mailbox_domains.cf
dbpath = /home/vmail/database/vmail.sqlite3
query  = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '0' AND active = '1';

File: /etc/postfix/sql/virtual_mailbox_maps.cf which fetch the list of mailboxes:

virtual_mailbox_maps.cf
dbpath = /home/vmail/database/vmail.sqlite3
query  = SELECT maildir FROM mailbox WHERE local_part='%u' AND domain='%d' AND active='1';

File: /etc/postfix/sql/virtual_alias_maps.cf which fetch the list of accounts and aliases:

virtual_alias_maps.cf
dbpath = /home/vmail/database/vmail.sqlite3
query  = SELECT goto FROM alias WHERE address='%s' AND active='1';

To ensure the above files are used by postfix, the following lines need to be added to the main.cf config file as show below.

main.cf: configuration

For more details on all the possible options, see Postfix documentation.

This is the overall file. Do not copy it blindly, double check everything, because there are comments that will cause postfix not to start if ignored:

main.cf
compatibility_level = 3.9

# Generic stuff
mail_owner = postfix
myhostname = mydomain.com
mydomain = mydomain.com <- this and the above line should be identical, not a typo!
myorigin = $mydomain
inet_interfaces = all
biff = no
message_size_limit = 0 <- this is unlimited, you might want to set a mail size limit here
disable_vrfy_command = yes
syslog_facility = mail
syslog_name = postfix

# Protection from lost mail
soft_bounce = yes <- switch to no in production
unknown_local_recipient_reject_code = 450 <- switch to 550 in production

# Important to keep as is to avoid delivery loops with the virtual domains
mydestination = localhost.localdomain
mynetworks_style = host

# Local delivery is actually managed by virtual delivery
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps

# Manage postfix virtual delivery mechanism via dovecot lmtp service
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = sqlite:/etc/postfix/sql/virtual_mailbox_domains.cf
virtual_mailbox_maps = sqlite:/etc/postfix/sql/virtual_mailbox_maps.cf
virtual_alias_maps = sqlite:/etc/postfix/sql/virtual_alias_maps.cf

# SMTPD (server) SASL + TLS setup
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = no
smtpd_tls_auth_only = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
smtpd_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/casa.gardiol.org/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/casa.gardiol.org/privkey.pem
smtpd_tls_mandatory_protocols = >=TLSv1.2
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache

# Generic access rules
strict_rfc821_envelopes = yes
smtpd_helo_required = yes
smtpd_reject_unlisted_sender = yes

# Client connection
smtpd_client_restrictions = permit_sasl_authenticated, reject
# HELO / EHLO filtering
smtpd_helo_restrictions = permit_sasl_authenticated, reject_unknown_helo_hostname
# MAIL FROM
smtpd_sender_restrictions = permit_sasl_authenticated, reject_unknown_sender_domain
# RCPT TO: (before recipient)
smtpd_relay_restrictions = permit_sasl_authenticated, reject_unauth_destination
# DATA
smtpd_data_restrictions = reject_unauth_pipelining
# RCPT TO: (after relay) add here spam checks (blacklists etc)
smtpd_recipient_restrictions = permit_sasl_authenticated

master.cf: configuration

The master.cf contains a list of the services (and ports) managed by Postfix on startup:

master.cf
smtp      inet  n       -       n       -       -       smtpd

submission inet n       -       n       -       -       smtpd

pickup    fifo  n       -       n       60      1       pickup
cleanup   unix  n       -       n       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       n       -       -       smtp
relay     unix  -       -       n       -       -       smtp
showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
retry     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache

Aliases

Before starting postfix you need to generate the aliases database:

newaliases

that's it.

Testing

To test Postfix you need your Dovecot to be running, so set it up, ensure Dovecot SASL is working, then come back here.

To generate a valid Base64 encoding for authentication see here.

To test your unencrypted SMTP service:

telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 gardiol.org ESMTP Postfix
EHLO mydomain.com
250-gardiol.org
250-PIPELINING
250-SIZE
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
quit
221 2.0.0 Bye
Connection closed by foreign host.

ensure that AUTH is not offered! Make sure there is no 250-AUTH PLAIN LOGIN in the output! This means you have successfully disabled SASL authentication on plain text connections.

To test SSL/TLS:

openssl s_client -starttls smtp -connect 127.0.0.1:587
Connecting to 127.0.0.1                                                                       
CONNECTED(00000003)                                                                           
 
[ ... long TLS handshake omissis ... ]
 
EHLO mydomain.com
250-mydomain.com
250-PIPELINING
250-SIZE
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH PLAIN -- never post your Base64 strings on internet! --
235 2.7.0 Authentication successful
MAIL FROM:<user@mydomain.com>
250 2.1.0 Ok
RCPT TO:<user@mydomain.com>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: My Test Email
Test email body
.
250 2.0.0 Ok: queued as 194869C1AB
quit
221 2.0.0 Bye
QUIT

Double check that you have that 250-AUTH PLAIN LOGIN, this means that you have properly setup SASL authentication using TLS.

To tets TLS without STARTLS, repeat the same command above without -starttls smtp.

You should now test that:

  • You can send an email from yourself to yourself
  • You can send an email from yourself to another mailbox of your domain
  • You can not send emails to other domains if you do not authenticate with SASL on TLS

That should do.

After you are done, go back to your main.cf disable soft_bounce and set 550 as error code instead of 450.

This website uses technical cookies only. No information is shared with anybody or used in any way but provide the website in your browser.

More information