How to configure TLS encryption in Postfix

Although Postfix (and the SMTP protocol in general) can function without any kind of encryption, enabling TLS it can be a good idea in terms of both security and privacy, so let’s look at how it can be easily done.

We’ll actually be configuring two separate types of encryption:

  • Opportunistic encryption for regular SMTP (port 25), both incoming 1 and outgoing 2. “Opportunistic”, here, means that the server will ask for encryption and use it if the other side also supports it, but if it doesn’t then it’ll work without encryption. Although forcing it might sound tempting for security reasons, in reality many “smaller” servers around the world still don’t support it, so you would be unable to send or receive mail to/from those. Opportunistic TLS at least means that most “big” email services (e.g. Gmail) will communicate with you (and you with them) with encryption.
  • Mandatory encryption for the submission service (port 587). This is used by your own users (even if it’s just you) to send mail through your server, and typically has different restrictions (e.g. it’s authenticated, but on the other hand it can be used to send mail to the outside (unlike incoming port 25 which doesn’t, as that would make it an open relay)). Both the users’ authentication that would otherwise be in clear text, and the fact that only a limited number of users (your users, too) will be accessing that port through email clients (never other email servers that you don’t control) make forcing encryption here a no-brainer.

NOTE: naturally, this is not an exhaustive Postfix tutorial. I’ll be assuming you already have a working server, and just want to add TLS encryption to it. Also, some parts may not apply to your case.

1. Have/get a TLS certificate for your email host’s public name

If you don’t already have one, see how to create a new TLS certificate. We’ll be using an RSA certificate here (instead of going with ECDSA) since unlike, say, a web server accessed by standard browsers, you can’t control what other email servers support 3, therefore it’s best to choose the most common option. 4

Note that the certificate’s CN must match your email host’s public name (e.g. “mail.domain.com“). That will also probably correspond to (one of) the domain’s MX records.

2. Postfix configuration

Again, I’ll be assuming your non-TLS Postfix is already working fine.

Put your certificate and key in /etc/postfix (for instance). For this example, I’ll be calling them myserver-full.crt and myserver.key.

In /etc/postfix/main.cf, add the following lines:

# TLS configuration starts here

tls_random_source = dev:/dev/urandom

# openssl_path=/usr/local/libressl/bin/openssl
# uncomment and edit the above if you're using a different "openssl" than the system's
# (in this case, LibreSSL)

# SMTP from your server to others
smtp_tls_key_file = /etc/postfix/myserver.key
smtp_tls_cert_file = /etc/postfix/myserver-full.crt
smtp_tls_CAfile = /etc/postfix/myserver-full.crt
smtp_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtp_tls_mandatory_protocols=!SSLv2,!SSLv3
smtp_tls_protocols=!SSLv2,!SSLv3
smtp_tls_loglevel = 1
smtp_tls_session_cache_database =
    btree:/var/lib/postfix/smtp_tls_session_cache

# SMTP from other servers to yours
smtpd_tls_key_file = /etc/postfix/myserver.key
smtpd_tls_cert_file = /etc/postfix/myserver-full.crt
smtpd_tls_CAfile = /etc/postfix/myserver-full.crt
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
smtpd_tls_protocols=!SSLv2,!SSLv3
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database =
    btree:/var/lib/postfix/smtpd_tls_session_cache

# TLS configuration ends here

And in /etc/postfix/master.cf, assuming you already have a “submission” section a bit like this:

submission  inet  n     -       n       -       -       smtpd
    -o smtpd_etrn_restrictions=reject
    -o smtpd_sasl_auth_enable=yes
    -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
    -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
    -o smtpd_helo_restrictions=permit_mynetworks,permit

Add to that section:

  -o smtpd_tls_security_level=encrypt

The above forces encryption for the submission service (remember that it’s not required for normal SMTP, it’s just desired).

In short:

  • your server tries to connect to others using TLS, but falls back to an unencrypted connection if the other side doesn’t support encryption;
  • other servers can connect to yours using TLS, but if they don’t attempt it then the connection will be unencrypted;
  • your users *must* use encryption (and authentication) to send mail through your server.

Restart your server, and check the logs: you should be getting mentions of TLS now. For instance, an email server starting an encrypted connection to yours looks like:

Sep 6 14:25:58 drax postfix/smtpd[22727]: Anonymous TLS connection established from lists.openbsd.org[192.43.244.163]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

Questions? Suggestions?

(And what about securing mailbox access? Enjoy: How to configure TLS encryption in Dovecot)

  1. emails sent to your users
  2. when your server, after accepting a new mail from a user of yours, sends it to its destination
  3. For instance, a Postfix configured with only an ECDSA certificate would not be able to “talk” securely with another Postfix with only an RSA cert, and they would have to fall back to an unencrypted connection. You might solve that by adding both types of certificates to your Postfix… but, then, only the RSA cert would ever be used, meaning there would be no point in doing that anyway…
  4. For the curious: the main difference here is that a web server or, say, an IMAP server only talk to clients (e.g. browsers, IMAP clients, etc., all of which typically support most types of encryption), while an SMTP server also connects to/receives connections from other servers (which are restricted to encryption types supported by the key/certificate pair that they’re using). And now you know. :)

17 Replies to “How to configure TLS encryption in Postfix”

  1. Great tutorial – nicely sized and runs through the essentials well.
    May be worth noting for users of a null client however, that the outbound SSL configuration or the submission block in the master.cf isn’t required to achieve encrypted outbound email.

  2. Very good tutorial.

    One note for Debian 9 users:
    smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_tls_session_cache

    Should be:
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

  3. i have followed the tutorial but still TLSv1 is enabled:
    Jun 11 15:50:32 smtp postfix/smtpd[8585]: setting up TLS connection from f18.immuniweb.com[64.15.129.117]
    Jun 11 15:50:32 smtp postfix/smtpd[8585]: Anonymous TLS connection established from f18.immuniweb.com[64.15.129.117]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)
    Jun 11 15:50:32 smtp postfix/smtpd[8585]: lost connection after STARTTLS from f18.immuniweb.com[64.15.129.117]

    my postfix is 2.5.5: OpenSSL 1.0.2s on Ubuntu 8.0.4.
    Any help will be appreciated .

    1. Hi Stefan,

      there is nothing in this tutorial to disable TLSv1; it only disables the (very insecure) SSL 2 and 3 protocols. With the configuration above, you should have TLSv1, v1.1 and v1.2 (and possibly v1.3 if using OpenSSL v1.1.1 or later) enabled.

      If you really want to disable TLSv1 (probably safe these days; on my email server, only spam bots typically use anything lower than v1.2), you should replace, in the tutorial above;

      smtp_tls_mandatory_protocols=!SSLv2,!SSLv3

      with:

      smtp_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1

      and:

      smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3

      with:

      smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1

       

  4. Hi Zurgl , Thanks for your prompt answer !

    I’ve already made different combinations as you proposed above but do not see anywhere in the mail.log something like in your log: “TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)” –>only TLSv1
    My worries is that the following servers generate the mark “F” when being tested via usual SSL / TLS test procedures (e.g. https://www.immuniweb.com/ssl/.

    I suppose this is due my smtp daemon use old library (I’ve recompile openssl in beginning as it was 0.9.8 )

    root@smtp:/etc/postfix# ldd /usr/lib/postfix/smtpd
    linux-gate.so.1 => (0xb7f9a000)
    libpostfix-master.so.1 => /usr/lib/libpostfix-master.so.1 (0xb7f88000)
    libpostfix-tls.so.1 => /usr/lib/libpostfix-tls.so.1 (0xb7f7a000)
    libpostfix-dns.so.1 => /usr/lib/libpostfix-dns.so.1 (0xb7f73000)
    libpostfix-global.so.1 => /usr/lib/libpostfix-global.so.1 (0xb7f42000)
    libpostfix-util.so.1 => /usr/lib/libpostfix-util.so.1 (0xb7f15000)
    libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8 (0xb7ed3000)
    libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7d91000)
    libsasl2.so.2 => /usr/lib/libsasl2.so.2 (0xb7d79000)
    libdb-4.7.so => /usr/lib/libdb-4.7.so (0xb7c25000)
    libnsl.so.1 => /lib/tls/i686/cmov/libnsl.so.1 (0xb7c0c000)
    libresolv.so.2 => /lib/tls/i686/cmov/libresolv.so.2 (0xb7bf6000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7a93000)
    libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7a8e000)
    libz.so.1 => /lib/libz.so.1 (0xb7a78000)
    libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7a5f000)
    /lib/ld-linux.so.2 (0xb7f9b000)

    1. Hi Stefan,

      First, yes, your Postfix is still using your old OpenSSL 0.9.8, as these lines from your ‘ldd’ show:

      libssl.so.0.9.8 => /usr/lib/i686/cmov/libssl.so.0.9.8 (0xb7ed3000)
      libcrypto.so.0.9.8 => /usr/lib/i686/cmov/libcrypto.so.0.9.8 (0xb7d91000)

      Assuming you don’t want to upgrade your entire system (which would be best, as your Ubuntu version is 11 years old), you’ll need to recompile your Postfix to use your alternative OpenSSL version instead of the system default. You may also need a newer Postfix than the one that came with your system.

      Also, I made a mistake in my tutorial above (which I’ve just corrected): the smtp/smtpd_tls_mandatory_protocols parameters affect mandatory encryption only (which is typically used for the submission service, on port 587). To affect opportunistic encryption (the one on port 25), you need the same parameters but without the “mandatory” part; i.e. something like:

      smtp_tls_protocols=!SSLv2, !SSLv3, !TLSv1
      smtpd_tls_protocols=!SSLv2, !SSLv3, !TLSv1

      (don’t remove the “mandatory” versions, though; keep them as well.)

  5. Hi, i changed my TLS connection in postfix from Untrusted TLS to Trusted TLS connection ( for servcer which have CA ), but what is difference between anonymous TLS connections ?

    1. Hi. It depends on whether you’re talking about Postfix as a client, or as a server. According to http://www.postfix.org/FORWARD_SECRECY_README.html#status:

      Anonymous (no peer certificate):

      – Postfix SMTP client: With opportunistic TLS (the “may” security level) the Postfix SMTP client does not verify any information in the peer certificate. In this case it enables and prefers anonymous cipher suites in which the remote SMTP server does not present a certificate (these ciphers offer forward secrecy of necessity). When the remote SMTP server also supports anonymous TLS, and agrees to such a cipher suite, the verification status will be logged as “Anonymous”.

      – Postfix SMTP server: This is by far most common, as client certificates are optional, and the Postfix SMTP server does not request client certificates by default (see smtpd_tls_ask_ccert). Even when client certificates are requested, the remote SMTP client might not send a certificate. Unlike the Postfix SMTP client, the Postfix SMTP server “anonymous” verification status does not imply that the cipher suite is anonymous, which corresponds to the server not sending a certificate.

      Untrusted (peer certificate not signed by trusted CA):

      – Postfix SMTP client: The remote SMTP server presented a certificate, but the Postfix SMTP client was unable to check the issuing CA signature. With opportunistic TLS this is common with remote SMTP servers that don’t support anonymous cipher suites.

      – Postfix SMTP server: The remote SMTP client presented a certificate, but the Postfix SMTP server was unable to check the issuing CA signature. This can happen when the server is configured to request client certificates (see smtpd_tls_ask_ccert).

      Trusted (peer certificate signed by trusted CA, unverified peer name):

      – Postfix SMTP client: The remote SMTP server’s certificate was signed by a CA that the Postfix SMTP client trusts, but either the client was not configured to verify the destination server name against the certificate, or the server certificate did not contain any matching names. This is common with opportunistic TLS (smtp_tls_security_level is “may” or else “dane” with no usable TLSA DNS records) when the Postfix SMTP client’s trusted CAs can verify the authenticity of the remote SMTP server’s certificate, but the client is not configured or unable to verify the server name.

      – Postfix SMTP server: The remote SMTP client certificate was signed by a CA that the Postfix SMTP server trusts. The Postfix SMTP server never verifies the remote SMTP client name against the names in the client certificate. Since the client chooses to connect to the server, the Postfix SMTP server has no expectation of a particular client hostname.

      Verified (peer certificate signed by trusted CA and verified peer name; or: peer certificate with expected public-key or certificate fingerprint):

      – Postfix SMTP client: The remote SMTP server’s certificate was signed by a CA that the Postfix SMTP client trusts, and the certificate name matches the destination or server name(s). The Postfix SMTP client was configured to require a verified name, otherwise the verification status would have been just “Trusted”.

      – Postfix SMTP client: The “Verified” status may also mean that the Postfix SMTP client successfully matched the expected fingerprint against the remote SMTP server public key or certificate. The expected fingerprint may come from smtp_tls_policy_maps or from TLSA (secure) DNS records. The Postfix SMTP client ignores the CA signature.

      – Postfix SMTP server: The status is never “Verified”, because the Postfix SMTP server never verifies the remote SMTP client name against the names in the client certificate, and because the Postfix SMTP server does not expect a specific fingerprint in the client public key or certificate.

      1. For all intents and purposes, “Untrusted” means that the other side has a self-signed certificate or the equivalent. In other words, it’s not “more authenticated” than “Anonymous”.

  6. In the section “In /etc/postfix/main.cf, add the following lines:” both “# SMTP from your server to others” and “# SMTP from other servers to yours” contain near identical configuration lines. Did you mean to choose one set or the other?

    1. They’re not really identical — the lines with “smtp” are about outgoing connections, while the ones with “smtpd” concern incoming connections.

  7. I do not see where MANDATORY vs OPPORTUNISTIC is differentiated in the instructions.
    I want to set up OPPORTUNISTIC.
    I see “your users *must* use encryption” and to me that implies MANDATORY encryption.

  8. Hi Guys,

    I have the below config in Postfix, Dovecot, Openssl and Nginx but still getting “Uses secure cipher: no” in https://www.paubox.com/secure-email-check test

    any idea how to disable this insecure ciphers in Cents 8, OpenSSL 1.1.1, if this is related.

    Postfix :

    smtp_tls_ciphers = high
    smtpd_tls_ciphers = high
    smtp_tls_mandatory_ciphers = high
    smtpd_tls_mandatory_ciphers = high
    smtp_tls_note_starttls_offer = yes
    smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

    smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
    smtpd_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
    smtp_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
    smtp_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL

    tls_high_cipherlist = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384

    Dovecot:
    ssl_min_protocol = TLSv1.2
    ssl_cipher_list = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384

    Nginx:

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384’

    opensslcnf.config

    CipherString = @SECLEVEL=2:kEECDH:kRSA:kEDH:kPSK:kDHEPSK:kECDHEPSK:-aDSS:-3DES:!DES:!RC4:!RC2:!IDEA:-SEED:!eNULL:!aNULL:!MD5:-SHA384:-CAMELLIA:-ARIA:-AESCCM8:!DES:!ADH:!RC4:!PSD:!SRP:!3DES
    Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
    MinProtocol = TLSv1.2
    MaxProtocol = TLSv1.3

    1. Hi,
      I’d take the Paubox test with a grain of salt — they don’t give any details about what “failed”.

      My own server, which gets an “A” on Immuniweb’s test, also fails the Paubox test:

      Vulnerable: Domain: drax.dehumanizer.com IP: 109.74.198.79 Priority: 10 Connection established: yes TLS: yes SSL: yes Cipher: TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Uses secure cipher: no

      You’ll note that the listed cipher is perfectly secure.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: