Skip to main content

Postfix

Postfix is the mail transfer agent (MTA) for kasad.com. It handles receiving emails, sending emails, access control, aliases, and more.

The only things Postfix does not handle are the storing of received emails and providing users access to stored emails. Both of those features are handled by Dovecot.

Architecture

The way Postfix works can be a little confusing. This section aims to provide just enough explanation of Postfix to make it possible to understand how we've set it up.

SMTP daemons

Postfix is an SMTP server. However in our setup, it actually serves three SMTP daemons:

Port Type Authentication enabled? Purpose
25 Plain SMTP Handles connnections from other MTAs. Mainly used to receive emails sent by users of other mail servers.
587 Submission ✓ (required) Handles connections from Mail User Agents (MUAs). Mainly used by users of the mail server to submit emails for Postfix to send to another MTA
465 Submission (over TLS) ✓ (required) Same as the previous submission daemon. The only differennce is this one uses an implicit TLS wrapper rather than starting with plaintext and using the STARTTLS command.

Since the two submission daemons perform the same task, we may refer to both of them as one submission daemon.

How Postfix handles mail

All mail that Postfix processes is sent to it via SMTP. That goes for both mail being sent to us from other MTAs as well as mail submitted by our users to be sent out to other MTAs.

So how do we know what's being received and what's to be sent?
The short answer is: we don't. Instead, Postfix processes all mail the same way. It's up to us to configure Postfix to permit/deny certain actions based on how we want mail to be processed.

Postfix can be used as a final destination server (like we're doing). It can also be used as a relay server, a backup mail server, a send-only server, a receive-only server, and probably much more. In our case, we will use Postfix as a final destination server for the kasad.com domain. We will also use it as a relay server for all other domains, but with restricted access.

Relaying mail

Relaying typically means receiving and re-sending mail to another destination. However, Postfix (confusingly) considers receiving mail a form of relaying. In a sense, it is being relayed from us to us.

Based on this, we want to implement the following rules:

  1. Allow other MTAs to relay mail to any user at the kasad.com domain without needing authentication
  2. Prevent other MTAs from relaying mail to recipients at other domains/MTAs
  3. Allow authenticated clients to relay mail to any domain as long as the From address is valid for their username
  4. Prevent even authenticated clients from relaying mail with a From address that our server doesn't "own"

If rule 1 was not in place, we wouldn't be able to receive mail from other servers because all incoming mail from unauthenticated clients (e.g. other MTAs) would be rejected.

If rule 2 was not in place, we would be allowing anyone on the Internet to send mail from our server to other servers. This is not only a bad idea for security reasons, but would likely also get us put on a banlist as spammers could use our server to send spam emails.

If rule 3 was not in place, Postfix would only be able to receive mail because it would be impossible to relay mail to other MTAs.

If rule 4 was not in place, any authenticated user would be allowed to send mail from our server using any From address. This would not only allow users to impersonate other users, but would also allow sending mail from addresses our server does not "own" which could also get us put on a banlist.

Understanding this concept of allowing different clients to relay mail to/from different places is necessary to understanding Postfix's configuration. While you could probably copy the provided configuration file and swap in your own domain, it is good to understand how the configuration works.

Installing Postfix

Install the mailutils, postfix, and postfix-pcre packages:

# apt install mailutils postfix postfix-pcre

When presented with the post-installation configuration menu, select the Internet site option. Then set the System mail name to your domain (kasad.com for us).

Enabling the service

The postfix package provides two systemd services: postfix.service and postfix@.service. The latter is used for multi-instance setups, where multiple Postfix instances run on the same server. It requires an instance name, e.g. postfix@instance1.service. The postfix.service unit is sort of a metaservice which does nothing on its own. Instead, all of the instance units are a "part of" the postfix.service unit, which makes the postfix.service unit control all of the instances.

In our case, we don't want multiple instances. We only want one main instance. For this, we use the - instance name:

# systemctl enable postfix.service postfix@-.service

Configuring Postfix

Within Postfix's configuration directory (/etc/postfix), there are two configuration files which Postfix will read:

  1. main.cf - Postfix configuration parameters. The main configuration file where settings are specified.
  2. master.cf - Postfix daemon processes. Configures which daemons Postfix will run.

Postfix is not a single program or daemon. Rather, it is a collection of multiple daemons which each provide a unique utility. They communicate and pass data between each other to provide a full Postfix setup.

Postfix can be used in many ways for many purposes. We want to use it as a final destination mail server for the kasad.com domain, while also using it as a relay server for sending mail (see above for details). We also want the mail accounts to map to UNIX user accounts, e.g. an email received for jett@kasad.com will be placed in a mail directory within the user jett's home directory. This is called local delivery.

Postfix supports other modes, like virtual delivery which we will not use.

main.cf

The following is the content of the main.cf configuration file. There are comments in the file to explain what all of the settings do. Some of the settings are also explained in further detail below.

# Listen on all interfaces
inet_interfaces = all

# Listen on both IPv4 and IPv6
inet_protocols = all

# Set the domain of the server
mydomain = kasad.com

# Set mail server hostname
myhostname = mail.kasad.com

# Domain to add to outgoing mail
myorigin = $mydomain

# Domains to use local(8) delivery for
mydestination = $myhostname, $mydomain, localhost

# Trust mail coming from the local host
mynetworks_style = host

# Don't use the local biff service for mail notifications
biff = no

# Generate "delayed mail" warnings
delay_warning_time = 2h
confirm_delay_cleared = yes

# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2

# TLS certificate/key
smtpd_tls_cert_file = /etc/letsencrypt/live/$mydomain/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/$mydomain/privkey.pem

# Only use TLSv1.2 or greater
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

# Set allowed TLS ciphers
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = aNULL

# Only permit SASL authentication over TLS connections
smtpd_tls_auth_only = yes

# Enable TLS for SMTP, but do not enforce it
# To enforce TLS for the SMTP server, add an entry for a specific port in
# master.cf
smtpd_tls_security_level = may
smtp_tls_security_level = may

# Log a summary of TLS handshakes
smtpd_tls_loglevel = 1
smtp_tls_loglevel = 1

# Include TLS information in 'Received' header of received mail
smtpd_tls_received_header = yes

# Enable SASL authentication
smtpd_sasl_auth_enable = yes

# Use the Dovecot plugin for SASL auth
smtpd_sasl_type = dovecot

# Implementation-specific information passed to the SASL auth plugin
smtpd_sasl_path = private/auth

# Don't allow anonymous logins, and only allow plaintext logins over TLS
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous

# Set restrictions for client connections to SMTPd on submission ports
# The $smtpd_client_restrictions option is set to this for submission daemons
# in master.cf
#   - permit_mynetworks: allow connections originating from $mynetworks
#   - permit_sasl_authenticated: allow connections from authenticated clients
#   - reject: reject everything else
mua_client_restrictions = permit_mynetworks,
                          permit_sasl_authenticated,
                          reject

# Set restrictions for relaying mail
#   - permit_mynetworks: allow mail originating from $mynetworks
#   - permit_sasl_authenticated: allow mail from authenticated clients
#   - reject_unauth_destination: reject mail addressed to an unauthorized destination
smtpd_relay_restrictions = permit_mynetworks,
                           permit_sasl_authenticated,
                           reject_unauth_destination

# Set restrictions for sending mail
#   - permit_mynetworks: allow mail originating from $mynetworks
#   - permit_sasl_authenticated: allow mail from authenticated clients
#   - reject_sender_login_mismatch: reject mail with a From address that
#     differs from the authenticated user's username
smtpd_sender_restrictions = permit_mynetworks,
                            reject_sender_login_mismatch,
                            permit_sasl_authenticated,
                            permit
smtpd_sender_login_maps = pcre:/etc/postfix/login_maps

# Aliases for local(8) delivery
alias_maps = hash:/etc/aliases

# Files for which databases will be generated when using the 'newaliases' command
alias_database = hash:/etc/aliases

# Aliases for virtual delivery (processed before local aliases)
virtual_alias_maps = hash:/etc/postfix/virtual

# No limit to mailbox size
mailbox_size_limit = 0

# Set the delimiter(s) between the user and extension
# E.g. mail addressed to 'user+extra' will go to the user 'user'
recipient_delimiter = +

# Set mailbox location for local(8) delivery
# (relative to recipient user's home directory)
home_mailbox = .mail/Inbox/

# Enable DKIM filter for mail
# Exact behavior depends on OpenDKIM configuration
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
milter_protocol = 6
milter_default_action = accept

# Command to use for delivering local mail
mailbox_command = /usr/lib/dovecot/deliver

# Set message size limit
#   52428800 = 50 MB
message_size_limit = 52428800

# Notify the postmaster of certain errors
#   - bounce: bounced (rejected) mail
#   - delay: delayed mail
#   - resource: mail not delivered due to resource problems
#   - software: mail not delivered due to software problems
notify_classes = bounce, delay, resource, software

# Filter for DSN emails
local_delivery_status_filter = pcre:/etc/postfix/local_dsn_filter

# Limit concurrent deliveries to local mailboxes
local_destination_concurrency_limit = 2

# vim: ft=pfmain ts=8 sw=8 et

Network interfaces

We want Postfix to listen on all network interfaces and all protocols so it is reachable on the Internet:

inet_interfaces = all
inet_protocols = all

Hostnames and domains

As explained in the Domain names section of the Email overview page, Postfix will operate as if its hostname is mail.kasad.com, as this is what we'll use for our MX DNS record. However, the domain name that we want to use for sending/receiving mail is kasad.com.

myhostname = mail.kasad.com
mydomain = kasad.com

The myorigin parameter controls the domain that local mail will be sent/delivered to. This is not really necessary when using Postfix as an Internet email server. It only affects sending mail to a user without a domain, e.g. mail to root will go to root@$myorigin.

myorigin = $mydomain

The mydestination parameter sets the list of domains that will use the local delivery method. We want to deliver all mail locally, as the mail accounts are all UNIX user accounts, so we specify the mail server's domain using the $mydomain variable, as well as the hostname and localhost.

mydestination = $mydomain, $myhostname, localhost

Trusted networks

Postfix keeps a list of trusted hosts, which are hosts that are allowed to relay mail through the Postfix server (i.e. send mail from our server to others). We don't want to allow any hosts to do this other than our own:

mynetworks_style = host

Delayed mail warnings

We want to notify users when their outgoing mail is delayed longer than 2 hours. We also want to send them a notifcation when the queue is finally processed and the delay is over.

delay_warning_time = 2h
confirm_delay_cleared = yes

TLS settings

We want to enable TLS for Postfix so its connections are encrypted, as we don't want mail being transferred in plaintext. This requires setting multiple configuration parameters, which are listed below.

While you may want to require TLS for all incoming connections, this is a bad idea. Many (especially older) email servers do not support TLS and will fail to deliver. According to RFC 2487, publicly-referenced email servers must not require connections to use TLS.

TLS certificate files

We use Certbot to obtain TLS certificates, so we need to point Postfix to that directory for the TLS certificate and key:

smtpd_tls_cert_file = /etc/letsencrypt/live/$mydomain/fullchain.pem
smtpd_tls_key_file  = /etc/letsencrypt/live/$mydomain/privkey.pem

TLS protocol versions

For connections to Postfix where TLS is mandatory, we require TLS v1.2 or higher:

smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

For Postfix version 3.6 and greater, you can set smtpd_tls_mandatory_protocols = >=TLSv1.2 which has the same effect.

To enable this restriction for all TLS connections, not just ones where TLS is mandatory, set the smtpd_tls_protocols option as well.

Require TLS when providing credentials

We don't want to allow users to submit their username/password over a plaintext connection. Instead, we tell Postfix to only announce and enable SASL login capability over TLS connections:

smtpd_tls_auth_only = yes

Note that this is different from requiring TLS for all incoming connections. Other mail servers may still connect without TLS to deliver mail; TLS is only required when authenticating and providing credentials.

Enable TLS for SMTP connections

We want to enable, but not enforce, TLS for both incoming and outgoing SMTP connections. Options with the smtp_ prefix control the Postfix SMTP client (i.e. for outgoing connections). Options with the smtpd_ prefix control the Postfix SMTP server (i.e. for incoming connections).

smtp_tls_security_level = may
smtpd_tls_security_level = may

TLS connection logging

We want to log a summary of each TLS handshake. This will allow us to see which connections have used TLS in the mail server logs.

smtp_tls_loglevel = 1
smtpd_tls_loglevel = 1

Include TLS information in Received headers

Postfix will generate a Received header for incoming mail with information about the server it was received from and the one it was received by. We want to include whether or not TLS was used in the information that gets stored in this header:

smtpd_tls_received_header = yes

SASL authentication

We want to enable SASL authentication in Postfix so users can log in and send emails. Postfix does not provide built-in SASL authentication. Instead, it uses an external provider. We'll use Dovecot as our SASL provider, since we're already using it as our IMAP server.

See the Postfix SASL connector section of the Dovecot page for information on how to configure Dovecot to provide SASL for Postfix.

In the Postfix configuration, the following options are needed:

smtpd_sasl_auth_enable = true
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

The following two settings ensure that anonymous logins are prohibited and that plaintext passwords are only sent over TLS connections. This is probably unnecessary, as we've restricted SASL to only be allowed over TLS connections in the first place.

smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous

MUA client connection rules

We only want to allow authenticated users to connect to the submission daemon. This is controlled using the $smtpd_client_restrictions parameter. However, we only want to apply this to the submission daemons and not the main SMTP daemon.

To do this, we will set a custom parameter, $mua_client_restrictions, in main.cf:

mua_client_restrictions = permit_mynetworks,
                          permit_sasl_authenticated,
                          reject

Then in master.cf, we must add the following option line to both submission daemon entries to assign this custom value to the $smtpd_client_restrictions parameter:

-o smtpd_client_restrictions=$mua_client_restrictions

The resulting entries in master.cf should look as follows:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_client_restrictions=$mua_client_restrictions
submissions inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/submissions
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=$mua_client_restrictions

Relay/recipient rules

This is possibly one of the most important configuration sections. The options in this section control what emails Postfix will permit the relaying or receiving of.

The smtpd_relay_restrictions option has a slightly misleading name. This parameter configures behavior not only for relaying, but also for sending and receiving. It is triggered when Postfix receives the RCPT TO SMTP command (i.e. whenever a mail is being sent, be that from or to a user on the local server). In other words, it applies rules to the recipient of an email.

smtpd_relay_restrictions = permit_mynetworks,
                           permit_sasl_authenticated,
                           reject_unauth_destination

The restrictions in the option above do the following (in order):

  1. It allows all mail originating from the local machine on which Postfix is running
  2. Allow mail originating from authenticated clients
  3. Reject mail going to an unauthorized destination (i.e. one not listed in $mydestination, $virtual_alias_domains, or $virtual_mailbox_domains)

This setting will allow mail from unauthenticated users as long as it is going to a domain listed in one of the three configuration options above. This allows mail servers on the Internet to send emails to users of the kasad.com mail server without authenticating. However, they will not be allowed to relay mail to other mail servers/domains, because we reject unauthorized destinations.

Next, we set the sender restrictions. This list of restrictions is triggered when Postfix receives the MAIL FROM SMTP command. In other words, this allows us to apply rules based on the sender of the email, whereas $smtpd_relay_restrictions applies to the recipient.

smtpd_sender_restrictions = permit_mynetworks,
                            reject_sender_login_mismatch,
                            permit_sasl_authenticated,
                            permit

The restrictions in this option do the following (in order):

  1. Allow mail originating from the local machine on which Postfix is running
  2. Reject mail which originates from an email address that does not match the authenticated user (see below)
  3. Allow mail from authenticated users
  4. Allow everything else that has not been rejected already

Since these rules are evaluated in order, rejection statements will prevent a subsequent allow statement from allowing an email. For example, if a login mismatch occurs, the mail will be rejected even if the user is authenticated, because reject_sender_login_mismatch comes before permit_sasl_authenticated. The same applies for if an allow statement comes first.

Preventing user impersonation

The permit_sasl_authenticated restriction in the $smtpd_sender_restrictions list will allow authenticated users to send emails. However, it will not place any restrictions on what From address they can use. This is bad, because the user jett could send an email from anh@kasad.com even though jett is not logged in as anh.

To fix this, we must do two things. The first was already dome when configuring $smtpd_sender_restrictions: the reject_sender_login_mismatch restriction must be specified, and it must be placed before the permit_sasl_authenticated restriction. The second thing we must do is configure the sender login map.

The $smtpd_sender_login_maps option specifies a list of tables which are used to map from sender email addresses to SASL login names that are allowed to use those addresses. Since we want to allow all users to send emails from <username>@kasad.com, it makes sense to use a regular expression (PCRE) lookup table:

smtpd_sender_login_maps = pcre:/etc/postfix/login_maps

We must then populate the file /etc/postfix/login_maps with our mappings:

/^(\w+)(\+[a-z0-9_+.-]+)?@kasad\.com$/  $1

This is a regular expression that will match <username>@kasad.com and <username>+<extension>@kasad.com and map both to <username>. Effectively, this allows all users to send emails from an address which consists of their address, an optional extension, and the domain part @kasad.com. See this breakdown for more details on how this works.

It is probably possible to not hard-code the domain here and to rely on the fact that Postfix will perform a lookup with just the user part if the entire email is not matched. However, this method works and so I have no incentive to change it.

Also see the Sending Emails from Web Apps page for information on adding users which are allowed to send emails from any user part at a specific subdomain (e.g. <anything>@books.kasad.com).

Address aliases

Postfix supports defining aliases which map addresses to other users/addresses for incoming mail. This means we can define an alias to forward email to www@kasad.com and postmaster@kasad.com to an actual user without having to set up accounts for those two email addresses. There are two types of supported aliases: local aliases and virtual aliases.

Local aliases

Local aliases are processed during local delivery and virtual ones when mail is first queued. Local delivery only occurs for domains in the $mydestination configuration parameter. They are looked up using only the user part. See aliases(5) for details. To enable local aliases, we set the following options:

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases

The first line tells Postfix where to look for aliases and the second tells it which file to generate when the newaliases command is run.

Virtual aliases

Virtual aliases are processed when mail is queued, meaning they get processed for all incominng emails, not just ones destined for $mydestination. Because of this, the virtual alias map can be used to host "virtual domains," i.e. domains that are either completely different from $mydomain or ones that are related but not part of $mydestination.

To enable virtual aliases, set the following option:

virtual_alias_maps = hash:/etc/postfix/virtual
Examples

The virtual alias table is where address rewriting should be done for subdomains that are not listed in $mydestination. For example, the following entry will redirect all emails addressed to intake@explorer.kasad.com to the explorer-intake local user:

intake@explorer.kasad.com	explorer-intake

Or the following would redirect all emails addressed to any user at the @explorer.kasad.com domain to the explorer-intake local user:

@explorer.kasad.com	explorer-intake

Regenerating the databases

When the /etc/aliases file is changed, the indexed database needs to be re-generated:

# newaliases

When the /etc/postfix/virtual file is changed, it also needs to be re-generated:

# postmap hash:/etc/postfix/virtual

User address extensions

Email addresses can be sectioned into two parts: the user part (everything before the @) and the domain part (everything after the @). The user part can optionally contain an extension. This extension is purely cosmetic. It does not change how the mail is delivered. To enable extensions, set the following option:

recipient_delimiter = +

The plus (+) character is the standard separator, so that's what we use. This setting will mean that any mail to user+anything@kasad.com will be treated as if it was sent to user@kasad.com.

Local delivery location

We want Postfix to store received emails in the .mail/Inbox directory within a user's home directory:

home_mailbox = .mail/Inbox/

This is ignored when $mailbox_command is set. We only specify it as a fallback/backup.

DKIM mail filter

We need mail to pass through the DKIM mail filter (or milter). See the DKIM Milter page for information on setting up the milter. Set the following options to have Postfix pass all mail (both incoming and outgoing) through the DKIM milter:

smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
milter_protocol = 6
milter_default_action = accept

The socket specified for the [non_]smtpd_milters options must match what is defined in the dkimpy-milter configuration file.

Using Dovecot for local delivery

We want to hand mail off to Dovecot for delivery rather than having Postfix deliver the mail itself. To do this, specify the following option:

mailbox_command = /usr/lib/dovecot/deliver

Message size limit

We want to enforce a maximum message size of 50 MiB. This will hopefully prevent DoS attacks and mailbox flooding.

message_size_limit = 52428800 # 50 MiB

Postmaster notifications

Postfix has the ability to send the postmaster a notification email when a failure occurs. We want to notify the postmaster of delayed messages, bounced messages, and failures due to software errors or limited resources:

notify_classes = bounce, delay, resource, software

Delivery status notification filter

Clients can request delivery status notifications for both failed and successfully sent emails. We don't want to reveal the internal commands or files being used, so we set a filter to replace that portion of the body in notification emails:

local_delivery_status_filter = pcre:/etc/postfix/local_dsn_filter

The contents of the /etc/postfix/local_dsn_filter file are:

/^: delivered to file.+/    mail queued for delivery
/^: delivered to command.+/ mail queued for delivery

master.cf

Postfix consists of a number of different daemons. Each daemon has its own purpose and exists independently from the others. All of Postfix's daemons are controlled by the master(8) daemon.

The master(8) daemon reads master.cf for a list of daemons for it to run. The contents of our master.cf file are listed below.

# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================

pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
  -o syslog_name=postfix/$service_name
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd

smtp      inet  n       -       y       -       -       smtpd
  -o smtpd_sasl_auth_enable=no
  -o content_filter=spamassassin
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/$service_name
  -o smtpd_tls_security_level=encrypt
  -o smtpd_client_restrictions=$mua_client_restrictions
submissions inet n      -       y       -       -       smtpd
  -o syslog_name=postfix/$service_name
  -o smtpd_tls_wrappermode=yes
  -o smtpd_client_restrictions=$mua_client_restrictions

spamassassin unix -     n       n       -       -       pipe
  user=debian-spamd argv=/usr/bin/spamc -e /usr/sbin/sendmail -G -oi -f ${sender} ${recipient}

Note: Lines beginning with whitespace are treated as a continuation of the previous line.

The entries in the file above are separated into three "blocks:"

Block #1 - Internal Postfix daemons

The first block enables the daemons required for Postfix to run successfully with our current configuration. These are mostly internal daemons or daemons to interface with utilities like postqueue(1).

Block #2 - SMTP daemons

The second block defines our three SMTP daemons (explained above). The first column, the service name, defines the port each daemon will listen on.* The port can be specified as a number or as a services(5) name. We also use the -o flag to override main.cf options for these specific daemons.

* This applies only for services of the inet type. For the unix type, the service name defines the name of the service's socket file.

Public SMTP daemon

  • We set $smtpd_sasl_auth_enable to no because we don't want to allow other MTAs to authenticate. We also want MUAs to use the submission port rather than the public SMTP port, so there's no need for authentication on the defualt SMTP port.
  • We also set the $content_filter with a value of spamassassin. This enables the SpamAssassin content filter for incoming mail. Only include this option if you've configured SpamAssassin on your server.

Submission daemon

The second SMTP server is the submission daemon.

  • We set $syslog_name to postfix/$service_name so we can tell which daemon might have errors. $service_name is replaced with the service name for the daemon.
  • We set $smtpd_tls_security to enncrypt, which will require clients to use TLS via the STARTTLS command after connecting.
  • Finally, we set $smtpd_client_restrictions to $mua_client_restrictions. See the MUA client connection rules section for details.

Submission over TLS daemon

The third SMTP server is another submission daemon which uses implicit TLS. This means that clients must directly connect using TLS. This is different from the other submission daemon, to which clients connect over plaintext TCP and begin a TLS session later.

  • Both $syslog_name and $smtpd_client_restrictions are set to the same values as for the first submission daemon. See the explanation above.
  • The $smtpd_tls_wrappermode option is enabled (yes), which enables wrapper-mode TLS. This is what we described above, where clients connect directly using TLS. In other words, the entire SMTP session is "wrapped" in TLS.

Block #3 - SpamAssassin content filter

Coming soon.