Postfix Mail Server

Postfix is the SMTP server of choice, used to send outgoing email messages to the world.

Howto

To see the mail queue:

mailq

To flush the queue and try to re-send all the messages:

postfix flush

To remove all mail from the queue:

postsuper -d ALL

To remove all mail marked as deferred in the queue:

postsuper -d ALL deferred

Display configuration

postconf -d

Local Mail Only

You can setup Postfix so that it doesn't send any outgoing email at all, but instead delivers everything locally to one user account.

Add this to Postfix's main.cf:

canonical_maps = regexp:/etc/postfix/canonical-redirect

and for the contents of the new file, choose the user and send all mail there:

/^.*$/ steve

Finally, reload or restart Postfix:

postfix reload

Source Build

Build with SASL and TLS support for using a third party SMTP relay server:

make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/include/sasl -DUSE_TLS -I/usr/include/openssl/" AUXLIBS="-lsasl2 -lssl -lcrypto"

Next, run make install. The defaults will place all the binaries in /usr as normal.

Logging

Logging can be made more verbose by editing /etc/postfix/master.cf and adding -v to the lines containing smtpd.

For example:

smtp      inet  n       -       n       -       -       smtpd -v

If creating a new /var/log/maillog you will need to restart your system logger in addition to postfix for it to populate.

Security

Enable Postfix to use TLS if possible. Clients and servers that connect may use it. In main.cf:

smtp_tls_security_level = may
smtpd_tls_security_level = may

If you have your own certs, enable those as well. In this case, the server.pem is the combination of the CRT PEM and the CA bundle PEM. Be sure to set the key to read-only for the root user as well.

cat beandog.crt.pem ca_bundle.pem > server.pem
smtpd_tls_cert_file = /etc/postfix/server.pem
smtpd_tls_key_file = /etc/postfix/server.key

Postfix can define which protocols and ciphers to ignore, and set the preferred order as well. Here, ignore TLSv1 and use stronger ciphers.

Also, if you are using OpenSSL 1.1.1 or higher, you can add TLSv1.3 to the list.

smtp_tls_ciphers = high
smtp_tls_mandatory_ciphers = high
smtp_tls_protocols = TLSv1.2, TLSv1.1, !TLSv1
smtp_tls_mandatory_protocols = TLSv1.2, TLSv1.1, !TLSv1

smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
smtpd_tls_protocols = TLSv1.2, TLSv1.1, !TLSv1
smtpd_tls_mandatory_protocols = TLSv1.2, TLSv1.1, !TLSv1

Specific ciphers can be disabled as well. For a list of all ciphers that are available, use openssl:

openssl ciphers

To make it easier to read, one per line:

openssl ciphers | tr ':' '\n'

You can find the ciphers or cipher family you'd like to drop by specifying the cipher list. For example::

openssl ciphers MD5:aNULL

And then disable those in main.cf:

smtp_tls_exclude_ciphers = MD5, aNULL
smtp_tls_mandatory_exclude_ciphers = MD5, aNULL

smtpd_tls_exclude_ciphers = MD5, aNULL
smtpd_tls_mandatory_exclude_ciphers = MD5, aNULL

Virtual Domains and Aliases

Configure Postfix to accept email from additional domains. In /etc/postfix/main.cf:

virtual_alias_domains = hash:/etc/postfix/virtual_domains
virtual_alias_maps = hash:/etc/postfix/virtual_aliases

In /etc/postfix/virtual_domains:

wonkabar.org comment-ignored

In /etc/postfix/virtual_aliases, send all email for wonkabar.org to user root on local box:

@wonkabar.org root

Create the database hashes once the files are created and reload postfix:

postmap virtual_domains
postmap virtual_aliases
postfix reload

Here's an example the maillog where an email sent to postmaster@wonkabar.org is delivered locally to user root@beandog.org:

Oct 28 20:52:11 lkmx postfix/local[29196]: 8A35EC93E1: to=<root@beandog.org>, orig_to=<postmaster@wonkabar.org>, relay=local, delay=0.05, delays=0.05/0/0/0, dsn=2.0.0, status=sent (delivered to mailbox)

FreeBSD

/etc/rc.d/sendmail stop
pkg_upgrade -r postfix
echo sendmail_enable="NO" >> /etc/rc.conf
echo sendmail_submit_enable="NO" >> /etc/rc.conf
echo sendmail_outbound_enable="NO" >> /etc/rc.conf
echo sendmail_msp_queue_enable="NO" >> /etc/rc.conf
echo daily_clean_hoststat_enable="NO" >> /etc/periodic.conf
echo daily_status_mail_rejects_enable="NO" >> /etc/periodic.conf
echo daily_status_include_submit_mailq="NO" >> /etc/periodic.conf
echo daily_submit_queuerun="NO" >> /etc/periodic.conf
echo postfix_enable="YES" >> /etc/rc.conf
/usr/local/etc/rc.d/postfix start

Configuration

When changing the Postfix configuration, you can either run postfix reload or restart it through the init system. If the changes are significant, or if postfix check complains, then restart it with init.

A default Postfix installation has a reasonable configuration.

Some common changes are:

  • myhostname
  • mydomain
  • myorigin
  • inet_interfaces
  • mydestination

Set smtp_tls_security_level to may so that TLS can be used to transfer mail.

# INTERNET HOST AND DOMAIN NAMES
# 
# The myhostname parameter specifies the internet hostname of this
# mail system. The default is to use the fully-qualified domain name
# from gethostname(). $myhostname is used as a default value for many
# other configuration parameters.
#
#myhostname = host.domain.tld
#myhostname = virtual.domain.tld

# The mydomain parameter specifies the local internet domain name.
# The default is to use $myhostname minus the first component.
# $mydomain is used as a default value for many other configuration
# parameters.
#
#mydomain = domain.tld

# SENDING MAIL
# 
# The myorigin parameter specifies the domain that locally-posted
# mail appears to come from. The default is to append $myhostname,
# which is fine for small sites.  If you run a domain with multiple
# machines, you should (1) change this to $mydomain and (2) set up
# a domain-wide alias database that aliases each user to
# user@that.users.mailhost.
#
# For the sake of consistency between sender and recipient addresses,
# myorigin also specifies the default domain name that is appended
# to recipient addresses that have no @domain part.
#
#myorigin = $myhostname
#myorigin = $mydomain

# RECEIVING MAIL

# The inet_interfaces parameter specifies the network interface
# addresses that this mail system receives mail on.  By default,
# the software claims all active interfaces on the machine. The
# parameter also controls delivery of mail to user@[ip.address].
#
# See also the proxy_interfaces parameter, for network addresses that
# are forwarded to us via a proxy or network address translator.
#
# Note: you need to stop/start Postfix when this parameter changes.
#
#inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = $myhostname, localhost

# The mydestination parameter specifies the list of domains that this
# machine considers itself the final destination for.
#
# These domains are routed to the delivery agent specified with the
# local_transport parameter setting. By default, that is the UNIX
# compatible delivery agent that lookups all recipients in /etc/passwd
# and /etc/aliases or their equivalent.
#
# The default is $myhostname + localhost.$mydomain.  On a mail domain
# gateway, you should also include $mydomain.
#
# Do not specify the names of virtual domains - those domains are
# specified elsewhere (see VIRTUAL_README).
#
# Do not specify the names of domains that this machine is backup MX
# host for. Specify those names via the relay_domains settings for
# the SMTP server, or use permit_mx_backup if you are lazy (see
# STANDARD_CONFIGURATION_README).
#
# The local machine is always the final destination for mail addressed
# to user@[the.net.work.address] of an interface that the mail system
# receives mail on (see the inet_interfaces parameter).
#
# Specify a list of host or domain names, /file/name or type:table
# patterns, separated by commas and/or whitespace. A /file/name
# pattern is replaced by its contents; a type:table is matched when
# a name matches a lookup key (the right-hand side is ignored).
# Continue long lines by starting the next line with whitespace.
#
# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
#
#mydestination = $myhostname, localhost.$mydomain, localhost
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
#       mail.$mydomain, www.$mydomain, ftp.$mydomain