MTA-STS: Enforcing TLS for Email in Transit
How to implement MTA-STS to prevent email interception and downgrade attacks. Practical deployment guide with SMTP TLS Reporting.
SMTP was designed in 1982-before encryption was a concern. Even with STARTTLS, opportunistic encryption can be stripped by attackers through downgrade attacks. MTA-STS (Mail Transfer Agent Strict Transport Security) solves this by publishing a policy that tells sending servers: "Always use TLS when delivering to this domain, and verify my certificate."
This guide covers practical MTA-STS implementation, including the companion SMTP TLS Reporting (TLS-RPT) standard that provides visibility into encryption failures.
The STARTTLS Problem
STARTTLS upgraded SMTP connections to encrypted TLS-a significant improvement over plaintext transmission. But it has a critical flaw: STARTTLS is opportunistic, not mandatory.
┌─────────────────────────────────────────────────────────────────────────┐
│ STARTTLS DOWNGRADE ATTACK │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ NORMAL FLOW │
│ ─────────── │
│ Sender ──────► Receiver │
│ EHLO │
│ ◄───── 250-STARTTLS │
│ STARTTLS │
│ ◄───── 220 Ready │
│ [TLS Handshake] │
│ 🔒 Encrypted SMTP Session │
│ │
│ ═══════════════════════════════════════════════════════════════════ │
│ │
│ ATTACK FLOW (MitM strips STARTTLS) │
│ ────────────────────────────────── │
│ Sender ──────► [Attacker] ──────► Receiver │
│ EHLO EHLO │
│ ◄───── 250 OK ◄───── 250-STARTTLS │
│ (no STARTTLS) (stripped!) │
│ DATA │
│ ◄───── 354 Go ahead │
│ 📧 Plaintext email... │
│ 👁️ Attacker reads everything │
│ │
└─────────────────────────────────────────────────────────────────────────┘
An attacker positioned between sender and receiver simply removes the STARTTLS advertisement. The sending server, seeing no STARTTLS support, transmits in plaintext. Neither party realizes the encryption was stripped.
MTA-STS prevents this by publishing policy out-of-band through HTTPS-a channel attackers can't silently manipulate.
How MTA-STS Works
MTA-STS uses two components:
- DNS TXT record: Signals policy existence and version
- Policy file: HTTPS-hosted file specifying enforcement mode
When a sending MTA prepares to deliver email, it:
- Checks for
_mta-sts.example.comTXT record - Fetches policy from
https://mta-sts.example.com/.well-known/mta-sts.txt - Caches the policy per its max_age directive
- Enforces TLS with certificate validation for subsequent deliveries
┌─────────────────────────────────────────────────────────────────────────┐
│ MTA-STS VALIDATION FLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Sending MTA Receiving Domain │
│ ─────────── ──────────────── │
│ │ │
│ │ 1. Check DNS TXT record │
│ │─────────────────────────────────► _mta-sts.example.com │
│ │◄───────────────────────────────── v=STSv1; id=20231215 │
│ │ │
│ │ 2. Fetch policy via HTTPS │
│ │─────────────────────────────────► mta-sts.example.com │
│ │◄───────────────────────────────── /.well-known/mta-sts.txt │
│ │ │
│ │ 3. Cache policy (max_age) │
│ │ [Policy stored locally] │
│ │ │
│ │ 4. Connect to MX with mandatory TLS │
│ │─────────────────────────────────► mail.example.com:25 │
│ │ STARTTLS (required) │
│ │ Verify certificate matches *.example.com │
│ │ ✓ Deliver email encrypted │
│ │ ✗ TLS failure → Reject (enforce mode) │
│ │ │
└─────────────────────────────────────────────────────────────────────────┘
Implementation Steps
Step 1: Verify Prerequisites
Before enabling MTA-STS, ensure your mail infrastructure supports it:
- Valid TLS certificates: All MX hosts must have valid, trusted certificates
- TLS 1.2 or higher: Older TLS versions should be disabled
- Certificate hostname matching: Certs must match MX hostnames
Test your current configuration:
# Check MX records
dig MX example.com +short
# Test TLS on each MX
openssl s_client -connect mail.example.com:25 -starttls smtp
# Verify certificate validity
echo | openssl s_client -connect mail.example.com:25 -starttls smtp 2>/dev/null | openssl x509 -noout -dates
Step 2: Create the Policy File
Create a policy file at the well-known path. Start with testing mode:
version: STSv1
mode: testing
mx: mail.example.com
mx: mail2.example.com
max_age: 86400
Policy fields:
| Field | Value | Description |
|---|---|---|
version | STSv1 | Protocol version (always STSv1) |
mode | testing/enforce/none | Policy strictness |
mx | hostname | Permitted MX hostnames (one per line) |
max_age | seconds | Cache duration (604800 = 1 week typical) |
Mode options:
testing- Report failures but deliver anywayenforce- Reject on TLS failurenone- Disable MTA-STS
Step 3: Host the Policy File
The policy must be served via HTTPS at:
https://mta-sts.example.com/.well-known/mta-sts.txt
Using Cloudflare Pages:
- Create a new Pages project
- Add
.well-known/mta-sts.txtwith your policy content - Set custom domain:
mta-sts.example.com
Using AWS S3 + CloudFront:
# Create S3 bucket
aws s3 mb s3://mta-sts.example.com
# Upload policy
aws s3 cp mta-sts.txt s3://mta-sts.example.com/.well-known/mta-sts.txt \
--content-type "text/plain"
# Configure CloudFront distribution with custom domain
Using GitHub Pages:
- Create repository
mta-sts - Add
.well-known/mta-sts.txt - Enable Pages with custom domain
mta-sts.example.com
Critical requirements:
- Valid HTTPS certificate (not self-signed)
- Content-Type:
text/plain - HTTPS only (HTTP must redirect or return error)
Step 4: Add DNS Records
Add the TXT record signaling MTA-STS availability:
_mta-sts.example.com. TXT "v=STSv1; id=20231215120000"
The id field is a version identifier. Update it whenever you change the policy-this signals senders to refresh their cached policy.
DNS configuration examples:
| Provider | Record Type | Name | Value |
|---|---|---|---|
| Cloudflare | TXT | _mta-sts | v=STSv1; id=20231215120000 |
| Route 53 | TXT | _mta-sts.example.com | "v=STSv1; id=20231215120000" |
| Google Domains | TXT | _mta-sts | v=STSv1; id=20231215120000 |
SMTP TLS Reporting (TLS-RPT)
TLS-RPT is the companion standard that provides visibility into TLS failures. Senders report connection problems-essential for identifying issues before enabling enforcement.
Configure TLS-RPT
Add a DNS TXT record requesting reports:
_smtp._tls.example.com. TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
Report delivery options:
| Method | Format | Configuration |
|---|---|---|
| JSON (gzipped) | rua=mailto:reports@example.com | |
| HTTPS | JSON POST | rua=https://reports.example.com/tls |
Understanding TLS Reports
Reports arrive as JSON, typically daily from major senders:
{
"organization-name": "Google Inc.",
"date-range": {
"start-datetime": "2023-12-15T00:00:00Z",
"end-datetime": "2023-12-15T23:59:59Z"
},
"policies": [
{
"policy": {
"policy-type": "sts",
"policy-domain": "example.com"
},
"summary": {
"total-successful-session-count": 1523,
"total-failure-session-count": 2
},
"failure-details": [
{
"result-type": "certificate-expired",
"sending-mta-ip": "192.0.2.1",
"failed-session-count": 2
}
]
}
]
}
Common failure types:
| Result Type | Cause | Action |
|---|---|---|
starttls-not-supported | MX doesn't offer STARTTLS | Enable STARTTLS |
certificate-expired | TLS cert expired | Renew certificate |
certificate-not-trusted | CA not trusted | Use trusted CA |
certificate-host-mismatch | Hostname doesn't match | Fix certificate SANs |
validation-failure | General TLS failure | Check TLS config |
Deployment Timeline
Week 1-2: Testing Mode
Deploy with mode: testing and monitor TLS-RPT:
version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
Review incoming reports. Common issues:
- Legacy systems without STARTTLS
- Certificate problems on backup MX
- Misconfigured load balancers terminating TLS
Week 3-4: Fix Issues
Address any failures identified in reports:
- Certificate issues: Renew, replace with trusted CA, or fix SANs
- Missing STARTTLS: Update server configuration
- Load balancer problems: Ensure TLS passthrough or proper re-encryption
Week 5+: Enforce Mode
Once reports show consistent success, enable enforcement:
version: STSv1
mode: enforce
mx: mail.example.com
mx: mail-backup.example.com
max_age: 604800
Update the DNS TXT record id to trigger policy refresh:
_mta-sts.example.com. TXT "v=STSv1; id=20240115enforce"
Troubleshooting
Policy Not Detected
# Verify DNS record
dig TXT _mta-sts.example.com +short
# Verify policy is accessible
curl -I https://mta-sts.example.com/.well-known/mta-sts.txt
TLS Failures in Reports
# Test STARTTLS
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.com
# Check certificate chain
openssl s_client -connect mail.example.com:25 -starttls smtp 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
MX Hostname Mismatch
Ensure the mx lines in your policy match your actual MX hostnames exactly. Wildcards aren't supported-list each MX explicitly.
MTA-STS for Major Providers
If you use hosted email, your provider may already support MTA-STS:
| Provider | MTA-STS Support | Configuration |
|---|---|---|
| Google Workspace | Built-in | Automatic with domain verification |
| Microsoft 365 | Built-in | Enabled via PowerShell |
| Fastmail | Built-in | Automatic |
| Zoho | Partial | Manual policy required |
For hosted providers, verify their MX hostnames and ensure your policy matches their infrastructure.
MTA-STS Best Practices
- Start in testing mode: Never go straight to enforce
- Monitor TLS-RPT: Reports reveal problems before they cause delivery failures
- Use reasonable max_age: 1 week (604800) balances caching with update flexibility
- Document all MX hosts: Missing an MX in policy causes failures
- Automate certificate renewal: Expired certs break enforcement
- Update id on changes: Senders cache aggressively-change id to force refresh
Complementary Standards
MTA-STS works alongside other email security standards:
| Standard | Purpose | Relationship |
|---|---|---|
| SPF/DKIM/DMARC | Sender authentication | Orthogonal (authentication vs. encryption) |
| DANE | TLS via DNSSEC | Alternative approach (requires DNSSEC) |
| BIMI | Brand logos | Requires DMARC, complements MTA-STS |
MTA-STS is generally easier to deploy than DANE (no DNSSEC dependency) and provides similar protection for the MX → receiver path.
Next Steps
MTA-STS protects email in transit-essential for any organization handling sensitive communications. Combined with DMARC for authentication and proper TLS configuration, you establish a comprehensive email security posture.
We help organizations implement complete email security stacks. Request an assessment to evaluate your current email infrastructure.
Questions about MTA-STS deployment for complex mail routing? We've handled multi-region setups, legacy gateway integrations, and hybrid Exchange environments. Contact us.