Docs / DNS & Domains / DANE: DNS-Based Authentication for Email TLS

DANE: DNS-Based Authentication for Email TLS

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 270 views · 4 min read

DANE (DNS-Based Authentication of Named Entities) uses DNSSEC-signed TLSA records to bind TLS certificates to DNS names, enabling email servers to verify each other's certificates without relying on certificate authorities. DANE provides the strongest transport security for email by ensuring both encryption and server authentication. This guide covers implementing DANE for email (SMTP).

How DANE Works

  1. Sending server looks up MX records for the recipient domain
  2. Queries TLSA records for the MX hostname (e.g., _25._tcp.mail.example.com)
  3. Connects to the mail server with STARTTLS
  4. Verifies the server's TLS certificate matches the TLSA record
  5. If verification succeeds, the connection is authenticated and encrypted

Prerequisites

  • DNSSEC-signed zone (DANE requires DNSSEC)
  • Mail server with valid TLS certificate
  • DNS server supporting TLSA records

Generating TLSA Records

# Method 1: Hash from certificate file
# TLSA usage 3 (DANE-EE), selector 1 (SubjectPublicKeyInfo), matching 1 (SHA-256)
openssl x509 -in /etc/letsencrypt/live/mail.example.com/cert.pem -noout -pubkey | \
    openssl pkey -pubin -outform DER | \
    openssl dgst -sha256 -binary | \
    xxd -p -c 64

# Output: a1b2c3d4e5f6...  (this is the certificate association data)

# Method 2: Using ldns-dane
ldns-dane create mail.example.com 25

# Method 3: Using hash-slinger
tlsa --create --selector 1 --mtype 1 mail.example.com

DNS Records

# TLSA record format:
# _port._protocol.hostname    TLSA    usage selector matching_type    certificate_data

# For the mail server at mail.example.com on port 25:
_25._tcp.mail.example.com.    TLSA    3 1 1 a1b2c3d4e5f6789012345678abcdef0123456789abcdef0123456789abcdef01

# Usage values:
# 0 (PKIX-TA) — CA constraint (must be issued by specified CA)
# 1 (PKIX-EE) — Service certificate constraint (must match AND be CA-valid)
# 2 (DANE-TA) — Trust anchor assertion (pin a CA, no PKIX validation needed)
# 3 (DANE-EE) — Domain-issued certificate (most common for self-hosted, no CA needed)

# Selector values:
# 0 — Full certificate
# 1 — SubjectPublicKeyInfo only (survives certificate renewal)

# Matching type:
# 0 — Exact match
# 1 — SHA-256 hash
# 2 — SHA-512 hash

# Recommended: 3 1 1 (DANE-EE, SPKI, SHA-256)
# This survives Let's Encrypt certificate renewals (key stays the same)

Postfix DANE Configuration

# /etc/postfix/main.cf

# Enable DANE for outgoing connections
smtp_dns_support_level = dnssec
smtp_tls_security_level = dane
smtp_tls_loglevel = 1

# For incoming connections (optional — verifies connecting servers)
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem

DNSSEC Setup (Required for DANE)

# If not already DNSSEC-signed, enable it in BIND:
dnssec-policy "default" {
    keys {
        ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
        zsk key-directory lifetime 30d algorithm ecdsap256sha256;
    };
};

zone "example.com" {
    type master;
    file "/etc/bind/zones/example.com.zone";
    dnssec-policy "default";
    inline-signing yes;
};

# Submit DS record to your registrar after signing

Testing DANE

# Check TLSA record exists
dig _25._tcp.mail.example.com TLSA +short

# Verify with ldns-dane
ldns-dane verify mail.example.com 25

# Test DANE with openssl
echo | openssl s_client -connect mail.example.com:25 -starttls smtp -dane_tlsa_domain mail.example.com -dane_tlsa_rrdata "3 1 1 a1b2c3..."

# Online DANE checker
# https://dane.sys4.de/smtp/example.com
# https://internet.nl/mail/example.com/

Handling Certificate Renewal

# When using TLSA 3 1 1 (DANE-EE with SPKI hash):
# The hash is based on the public key, not the certificate
# If Let's Encrypt renews with the SAME key → TLSA record stays valid
# If key changes → update TLSA record BEFORE deploying new cert

# Safe renewal workflow:
# 1. Generate new TLSA hash from new certificate
# 2. Add new TLSA record alongside old one
# 3. Wait for DNS propagation (TTL * 2)
# 4. Deploy new certificate
# 5. Remove old TLSA record after TTL expires

# Certbot hook for TLSA updates:
# /etc/letsencrypt/renewal-hooks/deploy/update-tlsa.sh
#!/bin/bash
NEW_HASH=$(openssl x509 -in "$RENEWED_LINEAGE/cert.pem" -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256 -binary | xxd -p -c 64)
# Update DNS via API or nsupdate

Best Practices

  • Use TLSA record type 3 1 1 (DANE-EE, SPKI, SHA-256) for email servers
  • Pin the public key (selector 1), not the full certificate — this survives renewals with the same key
  • Enable DNSSEC before adding TLSA records — DANE without DNSSEC is meaningless
  • Add TLSA records for both port 25 (MX) and port 587 (submission) if applicable
  • Monitor TLSA record validity — an incorrect TLSA record blocks all incoming DANE-verified email
  • Use two TLSA records during certificate rotation (old and new) to avoid downtime

Was this article helpful?