Jump to content

# Postfix

From ArchWiki

Related articles

- Postfix with SASL
- Virtual user mail system
- OpenDMARC
- OpenDKIM

Postfix is a mail transfer agent that according to its website:

  attempts to be fast, easy to administer, and secure, while at the same time being sendmail compatible enough to not upset existing users. Thus, the outside has a sendmail-ish flavor, but the inside is completely different.

This article builds upon Mail server. The goal of this article is to setup Postfix and explain what the basic configuration files do. There are instructions for setting up local system user-only delivery and a link to a guide for virtual user delivery.

## Installation

Install the postfix package.

## Configuration

See Postfix Basic Configuration. Configuration files are in `/etc/postfix` by default. The two most important files are:

- `master.cf`, defines what Postfix services are enabled and how clients connect to them, see master(5)
- `main.cf`, the main configuration file, see postconf(5)

Configuration changes need a `postfix.service` reload or run `postfix reload` in order to take effect.

### Aliases

See aliases(5).

You can specify aliases (also known as forwarders) in `/etc/postfix/aliases`.

You should map all mail addressed to root to another account since it is not a good idea to read mail as root.

Uncomment the following line, and change `you` to a real account.

    root: you

Once you have finished editing `/etc/postfix/aliases` you must run the postalias command:

     # postalias /etc/postfix/aliases

For later changes you can use:

     # newaliases

Tip Alternatively you can create the file `~/.forward`, e.g. `/root/.forward` for root. Specify the user to whom root mail should be forwarded, e.g. user@localhost.

    /root/.forward

    user@localhost

### Local mail

To only deliver mail to local system users (that are in `/etc/passwd`) update `/etc/postfix/main.cf` to reflect the following configuration. Uncomment, change, or add the following lines:

    myhostname = localhost
    mydomain = localdomain
    mydestination = $myhostname, localhost.$mydomain, localhost
    inet_interfaces = $myhostname, localhost
    mynetworks_style = host
    default_transport = error: outside mail is not deliverable

All other settings may remain unchanged. After setting up the above configuration file, you may wish to set up some #Aliases and then #Start Postfix.

### Virtual mail

Virtual mail is mail that does not map to a user account (`/etc/passwd`).

#### Virtual aliases

Virtual aliases are used to rewrite the destination addresses for all local, virtual and remote destinations. This can be used to rewrite the destination address for a single recipient, or an entire domain.

##### Virtual address aliases

Set up a virtual alias for a single address.

Enable the virtual alias table:

    /etc/postfix/main.cf

    virtual_alias_maps = lmdb:/etc/postfix/virtual

Populate the virtual alias table:

    /etc/postfix/virtual

    user@domain address

Rebuild the index file:

    # postmap /etc/postfix/virtual

Restart `postfix.service`.

### Check configuration

Run the `postfix check` command. It should output anything that you might have done wrong in a configuration file.

To see all of your configs, type `postconf`. To see how you differ from the defaults, try `postconf -n`.

## Start Postfix

Note You must run `newaliases` at least once for Postfix to run, even if you did not set up any #Aliases.

Start/enable the `postfix.service`.

## TLS

For more information, see Postfix TLS Support.

### Secure SMTP (sending)

By default, Postfix/sendmail will not send email encrypted to other SMTP servers. To use TLS when available, add the following line to `main.cf`:

    /etc/postfix/main.cf

    smtp_tls_security_level = may

To enforce TLS (and fail when the remote server does not support it), change `may` to `encrypt`. Note, however, that this violates RFC:2487 if the SMTP server is publicly referenced.

### Secure SMTP (receiving)

Warning If you deploy TLS, be sure to follow weakdh.org's guide to prevent FREAK/Logjam. Since mid-2015, the default settings have been safe against POODLE. For more information see Server-side TLS.

By default, Postfix will not accept secure mail.

You need to obtain a certificate. Point Postfix to your TLS certificates by adding the following lines to `main.cf`:

    /etc/postfix/main.cf

    smtpd_tls_security_level = may
    smtpd_use_tls = yes
    smtpd_tls_cert_file = /path/to/cert.pem
    smtpd_tls_key_file = /path/to/key.pem

There are two ways to accept secure mail. STARTTLS over SMTP (port 587 (also called "submission" port)) and SMTPS (port 465 (also called "submissions" port). The latter was previously deprecated but was reinstated by RFC:8314.

To enable STARTTLS over SMTP (port 587), uncomment the following lines in `master.cf`:

    /etc/postfix/master.cf

    submission inet n       -       n       -       -       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_reject_unlisted_recipient=no
    #  -o smtpd_client_restrictions=$mua_client_restrictions
    #  -o smtpd_helo_restrictions=$mua_helo_restrictions
    #  -o smtpd_sender_restrictions=$mua_sender_restrictions
      -o smtpd_relay_restrictions=
      -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
      -o milter_macro_daemon_name=ORIGINATING

The `smtpd_*_restrictions` options remain commented because `$mua_*_restrictions` are not defined in main.cf by default. If you do decide to set any of `$mua_*_restrictions`, uncomment those lines too.

To enable SMTPS (port 465), uncomment the following lines in `master.cf`:

    /etc/postfix/master.cf

    submissions     inet  n       -       n       -       -       smtpd
      -o syslog_name=postfix/smtps
      -o smtpd_tls_wrappermode=yes
      -o smtpd_sasl_auth_enable=yes
      -o smtpd_reject_unlisted_recipient=no
    #  -o smtpd_client_restrictions=$mua_client_restrictions
    #  -o smtpd_helo_restrictions=$mua_helo_restrictions
    #  -o smtpd_sender_restrictions=$mua_sender_restrictions
      -o smtpd_relay_restrictions=
      -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
      -o milter_macro_daemon_name=ORIGINATING

The rationale surrounding the `$smtpd_*_restrictions` lines is the same as above.

### Post-quantum TLS

As of Postfix 3.10 and OpenSSL 3.5.0, it is possible to offer post-quantum key exchanges for TLS. In order to do this, OpenSSL needs to be provided with a config file, as Postfix does not support the new keyshare syntax itself.

Note The post-quantum key exchange will only be used if both the sending and receiving server support it. Yet, there is no downside of enabling it - it will just be used opportunistically, if possible. Some larger services like GMail offer the X25519MLKEM768 keyshare already though. You can test whether a server supports any post-quantum algorithms by using testssl.sh or using the Hardenize web service.

To enable this functionality, add the following to your configuration (see [1]):

    /etc/postfix/main.cf

    tls_eecdh_auto_curves =
    tls_ffdhe_auto_groups =
    tls_config_file = ${config_directory}/openssl.cnf
    tls_config_name = postfix

Then you need to add an appropriate OpenSSL config:

    /etc/postfix/openssl.cnf

    postfix = postfix_settings
    [postfix_settings]
    ssl_conf = postfix_ssl_settings
    [postfix_ssl_settings]
    system_default = baseline_postfix_settings
    [baseline_postfix_settings]
    Groups = *X25519MLKEM768 / *X25519:X448 / P-256:P-384:P-521:ffdhe2048:ffdhe3072

This enables the new post-quantum secure X25519MLKEM768 as well as the previous defaults for traditional, non-quantum safe curves.

Note OpenSSL also supports further post-quantum exchanges like the hybrid schemes SecP256r1MLKEM768 and SecP384r1MLKEM1024 or using ML-KEM exclusively via MLKEM512, MLKEM768 and MLKEM1024. For now, hybrid schemes are preferred as they provide at least the same classical safety of X25519 and co should there be any issues found with ML-KEM or the implementation thereof. Considering these are pretty new algorithms, it appears as if X25519MLKEM768 is seeing most adoption for now. If wanted, any of the other key exchange schemes could be added though, their presence wouldn't cause any problems.

## Tips and tricks

### Blacklist incoming emails

Manually blacklisting incoming emails by sender address can easily be done with Postfix.

Create and open `/etc/postfix/blacklist_incoming` file and append sender email address:

    user@example.com REJECT

Then use the `postmap` command to create a database:

    # postmap lmdb:blacklist_incoming

Add the following code before the first permit rule in `main.cf`:

    smtpd_recipient_restrictions = check_sender_access lmdb:/etc/postfix/blacklist_incoming

Finally restart `postfix.service`.

### Hide the sender's IP and user agent in the Received header

This is a privacy concern mostly, if you use Thunderbird and send an email. The received header will contain your LAN and WAN IP and info about the email client you used. (Original source: AskUbuntu) What we want to do is remove the Received header from outgoing emails. This can be done by the following steps:

Add the following line to `main.cf`:

    smtp_header_checks = regexp:/etc/postfix/smtp_header_checks

Create `/etc/postfix/smtp_header_checks` with this content:

    /^Received: .*/     IGNORE
    /^User-Agent: .*/   IGNORE

Finally, restart `postfix.service`.

### Postfix in a chroot jail

The factual accuracy of this article or section is disputed.

Reason: This was added in 2016 and scarcely modified. This is probably much better done using systemd/Sandboxing features, specifically `RootDirectory=`.. (Discuss in Talk:Postfix)

Postfix is not put in a chroot jail by default. The Postfix documentation [2] provides details about how to accomplish such a jail. The steps are outlined below and are based on the chroot-setup script provided in the Postfix source code.

First, go into the `master.cf` file in the directory `/etc/postfix` and change all the chroot entries to 'yes' (y) except for the services `qmgr`, `proxymap`, `proxywrite`, `local`, and `virtual`

Second, create two functions that will help us later with copying files over into the chroot jail (see last step)

    $ alias CP="cp -p"

    cond_copy() {
      # find files as per pattern in $1
      # if any, copy to directory $2
      dir=$(dirname "$1")
      pat=$(basename "$1")
      lr=$(find "$dir" -maxdepth 1 -name "$pat")
      if test ! -d "$2" ; then exit 1 ; fi
      if test "x$lr" != "x" ; then $CP $1 "$2" ; fi
    }

Next, make the new directories for the jail:

    $ set -e
    $ umask 022
    $ POSTFIX_DIR=${POSTFIX_DIR-/var/spool/postfix}
    $ cd ${POSTFIX_DIR}
    $ mkdir -p etc lib usr/lib/zoneinfo
    $ test -d /lib64 && mkdir -p lib64

Find the localtime file:

    $ lt=/etc/localtime
    $ if test ! -f $lt ; then lt=/usr/lib/zoneinfo/localtime ; fi
    $ if test ! -f $lt ; then lt=/usr/share/zoneinfo/localtime ; fi
    $ if test ! -f $lt ; then echo "cannot find localtime" ; exit 1 ; fi
    $ rm -f etc/localtime

Copy localtime and some other system files into the chroot's etc

    $ CP -f $lt /etc/services /etc/resolv.conf /etc/nsswitch.conf etc
    $ CP -f /etc/host.conf /etc/hosts /etc/passwd etc
    $ ln -s -f /etc/localtime usr/lib/zoneinfo

Make sure resolv.conf is owned by root:

    $ chown root /var/spool/postfix/etc/resolv.conf

Copy required libraries into the chroot using the previously created function `cond_copy`

    $ cond_copy '/usr/lib/libnss_*.so*' lib
    $ cond_copy '/usr/lib/libresolv.so*' lib
    $ cond_copy '/usr/lib/libdb.so*' lib

And do not forget to reload Postfix.

### DANE (DNSSEC)

#### Resource record

Warning This is not a trivial section. Be aware that you make sure you know what you are doing. You better read Common Mistakes before.

DANE supports several types of records, however not all of them are suitable in Postfix.

Certificate usage 0 is unsupported, 1 is mapped to 3 and 2 is optional, thus it is recommendet to publish a "3" record. More on DANE#TLSA resource record.

#### Configuration

This article or section needs expansion.

Reason: What does tempfail mean? (Discuss in Talk:Postfix)

Opportunistic DANE is configured this way:

    /etc/postfix/main.cf

    smtpd_use_tls = yes
    smtp_dns_support_level = dnssec
    smtp_tls_security_level = dane

    /etc/postfix/master.cf

    dane       unix  -       -       n       -       -       smtp
      -o smtp_dns_support_level=dnssec
      -o smtp_tls_security_level=dane

To use per-domain policies, e.g. opportunistic DANE for example.org and mandatory DANE for example.com, use something like this:

    /etc/postfix/main.cf

    indexed = ${default_database_type}:${config_directory}/

    # Per-destination TLS policy
    #
    smtp_tls_policy_maps = ${indexed}tls_policy

    # default_transport = smtp, but some destinations are special:
    #
    transport_maps = ${indexed}transport

    transport

    example.com dane
    example.org dane

    tls_policy

    example.com dane-only

Note For global mandatory DANE, change `smtp_tls_security_level` to `dane-only`. Be aware that this makes Postfix tempfail (respond with a `4.X.X` error code) on all deliveries that do not use DANE at all!

Full documentation is found here.

## Extras

- PostfixAdmin — A web-based administrative interface for Postfix.

  https://postfixadmin.sourceforge.net/ || postfixadmin

### Postgrey

This article or section needs language, wiki syntax or style improvements. See Help:Style for reference.

Reason: See Help:Style (Discuss in Talk:Postfix)

Postgrey can be used to enable greylisting for a Postfix mail server.

#### Installation

Install the postgrey package. To get it running quickly edit the Postfix configuration file and add these lines:

    /etc/postfix/main.cf

    smtpd_recipient_restrictions =
      check_policy_service inet:127.0.0.1:10030

Then start/enable the `postgrey` service. Afterwards, reload the `postfix` service. Now greylisting should be enabled.

#### Configuration

Configuration is done by extending the unit `postgrey.service`.

#### Whitelisting

To add automatic whitelisting (successful deliveries are whitelisted and do not have to wait any more), add the `--auto-whitelist-clients=N` option and replace `N` by a suitably small number (or leave it at its default of 5).

    /etc/systemd/system/postgrey.service.d/override.conf

    [Service]
    ExecStart=
    ExecStart=/usr/bin/postgrey --inet=127.0.0.1:10030 \
           --pidfile=/run/postgrey/postgrey.pid \
           --group=postgrey --user=postgrey \
           --daemonize \
           --greylist-text="Greylisted for %%s seconds" \
           --auto-whitelist-clients

To add your own list of whitelisted clients in addition to the default ones, create the file `/etc/postfix/postgrey_whitelist_clients.local` and enter one host or domain per line, then restart `postgrey.service` so the changes take effect.

#### Troubleshooting

If you specify `--unix=/path/to/socket` and the socket file is not created ensure you have removed the default `--inet=127.0.0.1:10030` from the service file.

For a full documentation of possible options see `perldoc postgrey`.

### SpamAssassin

This section describes how to integrate SpamAssassin.

#### SpamAssassin stand-alone generic setup

Note If you want to combine SpamAssassin and Dovecot Mail Filtering, ignore the next two lines and continue further down instead.

Edit `/etc/postfix/master.cf` and add the content filter under smtp.

    smtp      inet  n       -       n       -       -       smtpd
      -o content_filter=spamassassin

Also add the following service entry for SpamAssassin

    spamassassin unix -     n       n       -       -       pipe
      flags=R user=spamd argv=/usr/bin/vendor_perl/spamc -e /usr/bin/sendmail -oi -f ${sender} ${recipient}

Now you can start and enable `spamassassin.service`.

#### SpamAssassin combined with Dovecot LDA / Sieve (Mailfiltering)

Set up LDA and the Sieve-Plugin as described in Dovecot#Sieve[broken link: invalid section]. But ignore the last line `mailbox_command...` .

Instead add a pipe in `/etc/postfix/master.cf`:

     dovecot   unix  -       n       n       -       -       pipe
           flags=DRhu user=vmail:vmail argv=/usr/bin/vendor_perl/spamc -u spamd -e /usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}

And activate it in `/etc/postfix/main.cf`:

     virtual_transport = dovecot

Alternately, if you do not want to use virtual transports you can use the mailbox_command. This runs with the local user and group, whereas the pipe runs with with the specified user using the `user` setting.

     mailbox_command = /usr/bin/vendor_perl/spamc -u spamd -e /usr/lib/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"

#### SpamAssassin combined with Dovecot LMTP / Sieve

Set up the LMTP and Sieve as described in Dovecot#Sieve[broken link: invalid section].

Edit `/etc/dovecot/conf.d/90-plugin.conf` and add:

     sieve_before = /etc/dovecot/sieve.before.d/
     sieve_extensions = +vnd.dovecot.filter
     sieve_plugins = sieve_extprograms
     sieve_filter_bin_dir = /etc/dovecot/sieve-filter
     sieve_filter_exec_timeout = 120s #this is often needed for the long running spamassassin scans, default is otherwise 10s

Create the directory and put spamassassin in as a binary that can be ran by dovecot:

     # mkdir /etc/dovecot/sieve-filter
     # ln -s /usr/bin/vendor_perl/spamc /etc/dovecot/sieve-filter/spamc

Create a new file, `/etc/dovecot/sieve.before.d/spamassassin.sieve` which contains:

     require [ "vnd.dovecot.filter" ];
     filter "spamc" [ "-d", "127.0.0.1", "--no-safe-fallback" ];

Compile the sieve rules `spamassassin.svbin`:

     # cd /etc/dovecot/sieve.before.d
     # sievec spamassassin.sieve

Finally, restart `dovecot.service`.

### Rule-based mail processing

With policy services one can easily finetune Postfix' behaviour of mail delivery. postfwd provides services to do so. This allows you to e.g. implement time-aware grey- and blacklisting of senders and receivers as well as SPF policy checking.

Policy services are standalone services and connected to Postfix like this:

    /etc/postfix/main.cf

    smtpd_recipient_restrictions =
      ...
      check_policy_service unix:/run/policyd.sock
      check_policy_service inet:127.0.0.1:10040

Placing policy services at the end of the queue reduces load, as only legitimate mails are processed. Be sure to place it before the first permit statement to catch all incoming messages.

### Sender Policy Framework

To use the Sender Policy Framework with Postfix, you can install python-spf-engineAUR, python-postfix-policyd-spfAUR or postfix-policyd-spf-perlAUR.

#### With spf-engine or python-postfix-policyd-spf

Edit `/etc/python-policyd-spf/policyd-spf.conf` to your needs. An extensively commented version can be found at `/etc/python-policyd-spf/policyd-spf.conf.commented`. Pay some extra attention to the HELO check policy, as standard settings strictly reject HELO failures.

In `main.cf` file, add a timeout for the policyd:

    /etc/postfix/main.cf

    policy-spf_time_limit = 3600s

Then add a transport

    /etc/postfix/master.cf

    policy-spf  unix  -       n       n       -       0       spawn user=nobody argv=/usr/bin/policyd-spf

Lastly you need to add the policyd to the `smtpd_recipient_restrictions`. To minimize load put it to the end of the restrictions but above any `reject_rbl_client` DNSBL line:

    /etc/postfix/main.cf

    smtpd_recipient_restrictions=
         ...
         permit_sasl_authenticated
         permit_mynetworks
         reject_unauth_destination
         check_policy_service unix:private/policy-spf

Now reload the `postfix` service.

You can test your setup with the following:

    /etc/python-policyd-spf/policyd-spf.conf

    defaultSeedOnly = 0

#### With postfix-policyd-spf-perl

Do the same process with postfix as with python-postfix-policyd-spf, but with the following differences:

Timeout for the policyd in `main.cf` file:

    /etc/postfix/main.cf

    policy_time_limit = 3600

Transport:

    /etc/postfix/master.cf

    policy  unix  -       n       n       -       0       spawn
         user=nobody argv=/usr/lib/postfix/postfix-policyd-spf-perl

Add the policyd to the `smtpd_recipient_restrictions`:

Warning Specify `check_policy_service` after `reject_unauth_destination` or else your system can become an open relay.

    /etc/postfix/main.cf

    smtpd_recipient_restrictions=
         ...
         reject_unauth_destination
         check_policy_service unix:private/policy
         ...

### Sender Rewriting Scheme

To use the Sender Rewriting Scheme with Postfix, install postsrsdAUR and adjust the settings:

    /etc/postsrsd/postsrsd.conf

    domains = { "yourdomain.tld", "yournextdomain.tld", "yournextdomain.tld" }
    unprivileged-user = "postsrsd"

Enable and start the daemon, making sure it runs after reboot as well. Then configure Postfix accordingly by tweaking the following lines:

    /etc/postfix/main.cf

    sender_canonical_maps = socketmap:unix:srs:forward
    sender_canonical_classes = envelope_sender
    recipient_canonical_maps = socketmap:unix:srs:reverse
    recipient_canonical_classes = envelope_recipient, header_recipient

Restart Postfix and start forwarding mail.

## Troubleshooting

### Warning: "database /etc/postfix/*.db is older than source file .."

If you get one or both warnings with journalctl:

    warning: database /etc/postfix/virtual.db is older than source file /etc/postfix/virtual
    warning: database /etc/postfix/transport.db is older than source file /etc/postfix/transport

Then you can fix it by using these commands, depending on the messages you get:

    postmap /etc/postfix/transport
    postmap /etc/postfix/virtual

And restart `postfix.service`.

### Host or domain name not found. Name service error for name=...

If you get the following warning with journalctl:

    Host or domain name not found. Name service error for name=...

It could be that you are running Postfix in a `chroot` and `/etc/resolv.conf` is missing. If so, you can fix this by:

    mkdir -p /var/spool/postfix/etc
    cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf

And restart `postfix.service`.

### error: require command: unknown Sieve capability `vnd.dovecot.filter'

    spamassassin: line 1: error: require command: unknown Sieve capability `vnd.dovecot.filter'.
    spamassassin: line 2: error: unknown command 'filter' (only reported once at first occurrence).
    spamassassin: error: validation failed.
    sievec(root): Fatal: failed to compile sieve script 'spamassassin.sieve'

If you get this error when running `sievec` after following #SpamAssassin combined with Dovecot LMTP / Sieve, replace `sieve_extensions` with `sieve_global_extensions` in `/etc/dovecot/sieve.before.d/spamassassin.sieve`.

Restart `dovecot.service`.

## See also

- Official documentation
- Postfix Ubuntu documentation
- Virtual user mail system with Postfix, Dovecot and Roundcube

Category:

- Mail server

Hidden categories:

- Pages or sections flagged with Template:Accuracy
- Pages or sections flagged with Template:Expansion
- Pages or sections flagged with Template:Style
- Pages with broken section links

Postfix
Add topic