When mail to a destination configured for mandatory TLS is delivered in plaintext, that is a security incident, not a delivery problem. Postfix TLS security levels exist to prevent this: at encrypt and above, the message should be deferred if TLS is unavailable, not silently downgraded. If plaintext delivery is happening where policy forbids it, the policy enforcement chain is broken.

The default logging makes this symptom nearly invisible. With smtp_tls_loglevel at its default of 0, no TLS negotiation details are logged for outbound connections. Failed handshakes and silent fallbacks to plaintext produce no log output at all. By the time someone notices, the policy violation may have been ongoing for hours or days.

What this means

Postfix applies TLS policy through a hierarchy of security levels. The distinction that matters for this symptom:

  • may (opportunistic TLS): Postfix attempts STARTTLS. If the remote server does not offer it, or if the handshake fails, Postfix retries the connection with TLS disabled. This is a silent fallback to plaintext.

  • encrypt (mandatory TLS): Postfix requires a successful TLS handshake. If the remote does not offer STARTTLS, or the handshake fails, the message is deferred. There is no fallback to plaintext. This is enforced via smtp_tls_security_level = encrypt or a per-domain smtp_tls_policy_maps entry.

  • verify and secure: Mandatory TLS plus hostname or trust chain verification. A peer that fails verification causes a deferral, not a fallback.

  • dane and dane-only: TLS policy derived from DNSSEC-validated TLSA records. dane falls back to opportunistic (may) if no TLSA records exist. dane-only is mandatory: no usable TLSA records means deferral.

A Postfix TLS downgrade means one of two things:

  1. A destination with a mandatory TLS policy (encrypt, verify, secure, dane-only) is receiving mail in plaintext. This should not happen under correct configuration. If it is, the policy is not being applied.

  2. A destination where you intended opportunistic TLS to succeed is silently falling back to plaintext. This is expected behavior at the may level, but if TLS was working before and stopped, it signals certificate problems, cipher mismatch, or network interception.

The first case is a page-worthy security incident. The second is a ticket for investigation.

flowchart TD
    A[Outbound message to destination] --> B{smtp_tls_policy_maps entry?}
    B -->|Yes| C{Policy level in map?}
    B -->|No| D{Global smtp_tls_security_level?}
    D -->|empty or none| E[Plaintext - no TLS attempted]
    D -->|may| F[Attempt STARTTLS]
    D -->|encrypt| G[Require STARTTLS]
    C -->|encrypt| G
    C -->|may| F
    C -->|dane-only| H[Require DNSSEC TLSA]
    F --> I{Handshake succeeds?}
    I -->|Yes| J[Deliver with TLS]
    I -->|No| K[Retry without TLS: silent plaintext]
    G --> L{Handshake succeeds?}
    L -->|Yes| J
    L -->|No| M[Defer message]
    H --> N{Valid TLSA found?}
    N -->|Yes| J
    N -->|No| M

Common causes

CauseWhat it looks likeFirst thing to check
Policy map not appliedsmtp_tls_policy_maps is empty or points to a stale file; mail to the “encrypt” destination goes out plaintextpostconf -h smtp_tls_policy_maps and postmap -q example.com <map>
Deprecated parameters conflictingsmtp_use_tls or smtp_enforce_tls set alongside smtp_tls_security_level; behavior does not match expectationspostconf -n | grep -E 'smtp_use_tls|smtp_enforce_tls|smtp_tls_per_site'
Broken TLSA or DANE recordsdane-only policy defers all mail to the destination; DNSSEC validation failure or stale TLSA recorddig +dnssec TLSA _25._tcp.mx.example.com and mail.log for “TLSA” or “DANE”
Active STARTTLS strippingOpportunistic TLS to a previously TLS-capable destination suddenly falls back to plaintext for all messagesopenssl s_client -starttls smtp -connect mx.example.com:25 from the MTA host
smtp_tls_mandatory_protocols too weak“encrypt” policy succeeds but negotiates TLSv1.0 instead of TLSv1.2 or higherRaise smtp_tls_loglevel to 1 and check the protocol version in logs

Quick checks

# Check current TLS security level for outbound mail
postconf -h smtp_tls_security_level

# Check if a TLS policy map is configured
postconf -h smtp_tls_policy_maps

# Query the policy map for a specific domain (replace map type and path)
postmap -q example.com hash:/etc/postfix/tls_policy

# Check TLS log level (default 0 means no TLS negotiation logging)
postconf -h smtp_tls_loglevel

# Look for deprecated TLS parameters still in active config
postconf -n | grep -E 'smtp_use_tls|smtp_enforce_tls|smtp_tls_per_site|smtp_tls_enforce_peername'

# Check mandatory protocols
postconf -h smtp_tls_mandatory_protocols

# Check mandatory ciphers
postconf -h smtp_tls_mandatory_ciphers

# Scan recent logs for TLS policy violations and verification failures
# Debian/Ubuntu: /var/log/mail.log  RHEL/CentOS: /var/log/maillog
grep -E 'TLS policy|SSL_connect error|verification failed|untrusted' /var/log/mail.log | tail -20

# Check for opportunistic TLS connections to unverified peers
grep 'Anonymous TLS connection established' /var/log/mail.log | tail -20

# Test STARTTLS availability to a specific destination from the MTA host
openssl s_client -starttls smtp -connect mx.example.com:25 </dev/null 2>/dev/null | head -20

How to diagnose it

  1. Confirm the outbound TLS policy is active. Run postconf -h smtp_tls_security_level and postconf -h smtp_tls_policy_maps. If the security level is empty or none, no outbound TLS policy is active at all. If a policy map is configured, verify the source file exists and has a current compiled counterpart (.db or .lmdb).

  2. Query the policy map for the affected domain. Use postmap -q <domain> <maptype>:<path>. If the query returns nothing, the domain has no entry and inherits the global smtp_tls_security_level. If the global level is may or empty, opportunistic TLS with silent plaintext fallback is the active policy for that destination.

  3. Check for deprecated parameters. The old-style TLS parameters (smtp_use_tls, smtp_enforce_tls, smtp_tls_per_site, smtp_tls_enforce_peername) were replaced by smtp_tls_security_level in Postfix 2.3. If these coexist with smtp_tls_security_level, behavior may not match expectations. smtp_tls_per_site is ignored when smtp_tls_policy_maps is non-empty, but Postfix logs a warning if both are configured.

  4. Raise TLS logging temporarily. Set smtp_tls_loglevel = 1 and run postfix reload. This logs TLS negotiation details for outbound connections without excessive verbosity. Level 2 dumps the full TLS handshake and is useful for cipher debugging but too noisy for sustained production use. Set it back to 0 after diagnosis, or leave at 1 permanently for ongoing visibility (recommended in Prevention below).

  5. Watch the logs for the affected destination. After raising the log level, send or wait for a test message. Look for these patterns:

    • Anonymous TLS connection established: opportunistic TLS to an unverified peer. Expected at may. If you see this for an encrypt destination, the policy is not being enforced.
    • TLS policy: ... digest does not match: DANE or fingerprint verification failure.
    • SSL_connect error: handshake failure. At encrypt, this should be followed by a deferral, not a plaintext retry.
    • Untrusted TLS connection established: TLS succeeded but the peer certificate was not verified. Expected at encrypt. Wrong at verify or secure.
  6. Test STARTTLS from the MTA host. Run openssl s_client -starttls smtp -connect mx.example.com:25 from the Postfix server. If STARTTLS is not offered by the remote, an encrypt policy should defer. If STARTTLS is offered but the handshake fails, check certificate chain, protocol version, and cipher compatibility.

  7. Check DANE or TLSA records if applicable. For dane or dane-only policies, verify TLSA records exist and are DNSSEC-signed: dig +dnssec TLSA _25._tcp.mx.example.com. A stale or malformed TLSA record causes dane-only to defer all mail, and causes dane to fall back to opportunistic may.

Metrics and signals to monitor

SignalWhy it mattersWarning sign
TLS negotiation failure rateSustained failures indicate certificate, cipher, or network interception problemsMandatory TLS: any failure. Opportunistic: above 5% failure rate
Deferred queue growth from TLS failuresTLS handshake failures at encrypt cause deferrals, not silent fallbackDeferred messages with “TLS” or “SSL” in the reason string
Anonymous TLS connection log frequencyIndicates opportunistic TLS to unverified peers; a spike may mean TLS was previously succeeding but stoppedSudden increase for destinations that previously showed verified TLS
Certificate expiration (outbound)Expired client or server certificates break mandatory TLSExpiration within 30 days for any certificate in the trust chain
smtp_tls_mandatory_protocols valueDefault may allow TLSv1.0 and TLSv1.1Value does not exclude SSLv2, SSLv3, TLSv1, and TLSv1.1
DANE and TLSA record validityBroken TLSA records cause dane-only deferrals or fallback to may under daneDNSSEC validation failures or missing TLSA records for DANE-policy destinations

Fixes

Policy map missing or stale

If smtp_tls_policy_maps is empty or the map file does not contain the affected domain, create or update the entry:

# /etc/postfix/tls_policy
example.com encrypt

Rebuild the map and reload:

# Rebuild the policy map and reload Postfix
postmap /etc/postfix/tls_policy
postfix reload

Verify with postmap -q example.com hash:/etc/postfix/tls_policy.

Deprecated parameters causing confusion

Remove smtp_use_tls, smtp_enforce_tls, smtp_tls_per_site, and smtp_tls_enforce_peername from main.cf. Replace them with smtp_tls_security_level and smtp_tls_policy_maps. After changes, run postfix reload and verify with postconf -n.

Weak mandatory protocols

The upstream default for smtp_tls_mandatory_protocols may allow TLSv1.0 and TLSv1.1. Explicitly restrict mandatory protocols:

# WARNING: these commands modify main.cf directly.
# Back up your configuration first if you are not using version control.
postconf -e 'smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
postconf -e 'smtp_tls_mandatory_ciphers = high'
postfix reload

Broken TLSA or DANE records

If using dane-only and TLSA records are broken or missing, mail defers until the records are fixed. This is correct behavior. Do not lower the policy to work around it. Coordinate with the destination’s DNS administrator to publish valid, DNSSEC-signed TLSA records.

If using dane (opportunistic DANE), missing TLSA records cause fallback to may, which is expected. But if TLSA records previously existed and disappeared, investigate DNSSEC validation failures or zone misconfiguration on the destination side.

Active STARTTLS stripping

If STARTTLS is stripped for a specific destination but works from other network paths, this may indicate active interception. Verify by testing from multiple vantage points. The protections against STARTTLS stripping are DANE (dane-only with valid TLSA records) or MTA-STS, both of which make the stripping detectable rather than silent.

Postfix has native DANE support since version 2.11. MTA-STS requires an external resolver plugin such as postfix-tlspol or postfix-mta-sts-resolver.

Prevention

  • Keep smtp_tls_loglevel = 1 permanently. Level 0 hides all TLS negotiation for outbound mail. The extra log volume is minimal, and the visibility is critical for detecting silent fallbacks.

  • Audit smtp_tls_policy_maps regularly. Run postmap -q <domain> <map> for each mandatory-TLS destination to confirm entries resolve correctly. Stale map files after infrastructure changes are a common cause of unintended plaintext delivery.

  • Periodically check for deprecated parameters. Run postconf -n | grep -E 'smtp_use_tls|smtp_enforce_tls|smtp_tls_per_site|smtp_tls_enforce_peername' after any Postfix upgrade or configuration change.

  • Monitor certificate expiration for outbound TLS. Track the SMTPD server certificate, any client certificates, and the CA chains used for mutual TLS to relay hosts. Certificate expiry is the most common cause of mandatory-TLS breakage.

  • Prefer DANE (dane-only) for mandatory enforcement. DNSSEC-anchored TLSA records resist STARTTLS stripping without requiring a separate policy map file that can go stale.

How Netdata helps

  • Per-second log parsing of Postfix mail logs surfaces TLS negotiation failures, Anonymous TLS connection events, and SSL_connect error patterns as they happen, rather than relying on periodic manual log scans.

  • Deferred queue growth rate correlated with TLS failure logs distinguishes a mandatory-TLS deferral storm (policy working correctly, remote is broken) from a silent plaintext fallback (policy not being applied).

  • Anomaly detection on TLS success and failure ratios flags sudden shifts in TLS posture for specific destinations.

  • Certificate expiration monitoring for the SMTPD listener and any client certificates provides early warning before mandatory TLS breaks.