How to enforce sending encrypted e-mails with TLS (SMTP over TLS) in Postfix

Written by - 1 comments

Published on - last updated on March 4th 2026 - Listed in Linux Internet Mail


By default, Postfix does not encrypt outgoing e-mails. In case of a man-in-the-middle-attacks, this can be a security issue.

Configure Postfix to use TLS encryption when sending e-mails.

Enforcing TLS on all outgoing e-mails 

By setting the following parameter in /etc/postfix/main.cf, all outgoing e-mails (to any destination) will be encrypted with TLS:

smtp_tls_security_level = encrypt

Note: The old and (in 2026) deprecated option was "smtpd_use_tls". This option will be removed in future Postfix versions.  

But this brings another problem: Many mail servers do not accept TLS connections. E-mails to such mail servers will therefore not be sent.

Use TLS - if supported by the recipient server 

As an alternative, one can set smtp_tls_security_level = may - with this setting, TLS encryption is only used, if the recipient server accepts TLS connections.

Enforce TLS only on specific destination domains 

In some circumstances, it is necessary to enforce TLS connections to specific domains. That's what I had to do today. While looking through the Postfix documentation, I got aware of the TLS Policy Table. This setting allows to define TLS connections on a per-domain basis.

Example: You want to enforce TLS on all e-mails sent to *@example.com. The MX of example.com is receive.example.com.

First, create the tls_policy file and enter the specific domain followed by the TLS option. Then create the hash database of that file:

root@postfix:~# touch /etc/postfix/tls_policy

root@postfix:~# echo "example.com   encrypt" > /etc/postfix/tls_policy

root@postfix:~# postmap /etc/postfix/tls_policy

Now you need to tell Postfix to use a TLS Policy Table. You define that in /etc/postfix/main.cf:

root@postfix:~# cat /etc/postfix/main.cf | grep tls_policy
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy

Reload Postfix (restart is not necessary), to use TLS Policy Table:

root@postfix:~# /etc/init.d/postfix reload

On newer systems:

root@postfix:~# systemctl reload postfix

Postfix log comparison (without and with TLS) 

Let's see how it looks in the logs, when Postfix sends an e-mail (debug_peer activated).

LOG OUTPUT WITHOUT TLS:

postfix/pickup[28256]: 4CAEB11560005: uid=0 from=
postfix/cleanup[28257]: 4CAEB11560005: message-id=<20120803074914.4CAEB11560005@send.example.com>
postfix/qmgr[28259]: 4CAEB11560005: from=, size=330, nrcpt=1 (queue active)
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 220 area-1.ch ESMTP Postfix (Debian/GNU)
postfix/smtp[28260]: > send.example.com[192.168.10.20]:25: EHLO send.example.com
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-area-1.ch
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-PIPELINING
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-SIZE 36700160
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-VRFY
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-ETRN
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-STARTTLS
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-AUTH PLAIN LOGIN
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-ENHANCEDSTATUSCODES
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250-8BITMIME
postfix/smtp[28260]: < receive.example.com[192.168.10.10]:25: 250 DSN
postfix/smtp[28260]: server features: 0x901f size 36700160       
postfix/smtp[28260]: Using ESMTP PIPELINING, TCP send buffer size is 4096
postfix/smtp[28260]: > send.example.com[192.168.10.20]:25: MAIL FROM: SIZE=330
...

LOG OUTPUT WITH TLS:

postfix/pickup[28066]: 4057311560005: uid=0 from=
postfix/cleanup[28067]: 4057311560005: message-id=<20120803074748.4057311560005@send.example.com>
postfix/qmgr[28069]: 4057311560005: from=, size=330, nrcpt=1 (queue active)
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 220 area-1.ch ESMTP Postfix (Debian/GNU)
postfix/smtp[28070]: > send.example.com[192.168.10.20]:25: EHLO send.example.com
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-area-1.ch
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-PIPELINING
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-SIZE 36700160
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-VRFY
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-ETRN
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-STARTTLS
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-AUTH PLAIN LOGIN
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-ENHANCEDSTATUSCODES
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250-8BITMIME
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 250 DSN
postfix/smtp[28070]: server features: 0x901f size 36700160
postfix/smtp[28070]: Using ESMTP PIPELINING, TCP send buffer size is 4096
postfix/smtp[28070]: > send.example.com[192.168.10.20]:25: STARTTLS
postfix/smtp[28070]: < receive.example.com[192.168.10.10]:25: 220 2.0.0 Ready to start TLS
postfix/smtp[28070]: send attr request = lookup
postfix/smtp[28070]: send attr cache_type = smtp
postfix/smtp[28070]: send attr cache_id = smtp:192.168.10.10:25:area-1.ch&p=1&c=ALL:!EXPORT:!LOW:+RC4:@STRENGTH:!eNULL
postfix/smtp[28070]: private/tlsmgr: wanted attribute: status
...

Note that the sending server "tells" the recipient server (area-1.ch) to use TLS (STARTTLS) and area-1.ch confirms. This is then followed by the TLS encryption itself.

Increase connection security (encrypt -> secure)

As I've defined "encrypt" as value for the smtpd_tls_security_level option, this means, that TLS is enforced and all server certificates of the recipient server are accepted, including self-signed certificates.

If you're suspicious, you can set the TLS option to the highest value: secure. With secure, the server certificate on the recipient side MUST be issued by a known Certificate Issuer (e.g. VeriSign), otherwise the mail will not be sent and will stay in the mail queue:

...
postfix/smtp[28515]: input attribute value: z0FpDdCLPEJc225tMd0BI5CHP28PkTUD36/TT+YU5bI=
postfix/smtp[28515]: private/tlsmgr: wanted attribute: (list terminator)
postfix/smtp[28515]: input attribute name: (end)
postfix/smtp[28515]: certificate verification failed for receive.example.com[192.168.10.10]:25: untrusted issuer /C=CH/ST=Geneva /L=Geneva/O=Claudio Kuenzler/OU=Claudio Kuenzler/CN=receive.example.com
postfix/smtp[28515]: send attr request = update
postfix/smtp[28515]: send attr cache_type = smtp
postfix/smtp[28515]: send attr session = [data 1712 bytes]
...

root@postfix:~# mailq
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
5626511560005      330 Fri Aug  3 09:50:15  root@send.example.com 
                                              (Server certificate not trusted)
                                         recipient@receive.example.com


Add a comment

Show form to leave a comment

Comments (newest first)

Sebastian from Germany wrote on Dec 1st, 2015:

Thanks, it works well but I needed to add the domain from "tls_policy" to "transport" file to get it to work. Otherwise postfix sends all mails to our standard relay host.


RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Observability   Office   OpenSearch   PHP   Perl   Personal   PostgreSQL   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder