Mail Transfer Agent Strict Transport Security (MTA-STS) addresses a critical vulnerability in email transport. SMTP encryption has traditionally been optional, allowing downgrade attacks.
MTA-STS lets you declare that your mail servers require TLS. Sending servers must refuse delivery over unencrypted connections.
What is MTA-STS?
MTA-STS (RFC 8461) enables domain owners to enforce TLS encryption for incoming email. Unlike opportunistic TLS, it prevents fallback to plaintext.
How MTA-STS Works
MTA-STS uses two components:
- DNS TXT Record - Indicates MTA-STS is enabled
- Policy File - Specifies enforcement details
DNS Record:
_mta-sts.example.com. IN TXT "v=STSv1; id=20250117001"
Policy File Location:
https://mta-sts.example.com/.well-known/mta-sts.txt
Policy File Format
version: STSv1
mode: enforce
mx: mail.example.com
mx: mail2.example.com
max_age: 604800
| Field | Description |
|---|---|
version | Always STSv1 |
mode | none, testing, or enforce |
mx | Authorized mail servers |
max_age | Cache duration in seconds |
Policy Modes
| Mode | Behavior |
|---|---|
none | MTA-STS disabled |
testing | Report failures, don't enforce |
enforce | Require TLS, fail if unavailable |
Why Implement MTA-STS?
MTA-STS addresses the SMTP downgrade attack and other security gaps.
Preventing Downgrade Attacks
In a typical attack:
- Attacker intercepts SMTP connection
- Removes STARTTLS from server response
- Sending server believes encryption unavailable
- Email transmitted in plaintext
- Attacker reads or modifies message
Handling Legitimate Failures
Opportunistic TLS fails silently in legitimate scenarios:
- Misconfigured servers
- Expired certificates
- Network issues
MTA-STS ensures failures result in delivery abort, not security compromise.
Mail Server Verification
MTA-STS specifies which servers can receive your mail:
mx: mail.example.com
mx: mail2.example.com
This adds protection against DNS spoofing attacks.
Major Provider Support
Google, Microsoft, and Yahoo support MTA-STS. Implementing it ensures maximum protection with these providers.
How to Configure MTA-STS
MTA-STS requires both DNS and web hosting configuration.
Step 1: Create the Policy File
Create a text file with your policy:
version: STSv1
mode: testing
mx: mail.example.com
mx: mail2.example.com
max_age: 86400
mode: testing to gather data before enforcing.Important requirements:
- List all MX hosts exactly as they appear in DNS
- Use
max_agein seconds (86400 = 24 hours) - File must be plain text
Step 2: Host the Policy File
Host the file at the exact path:
https://mta-sts.example.com/.well-known/mta-sts.txt
Requirements:
- Valid HTTPS certificate for
mta-sts.example.com - Publicly accessible
- Correct MIME type (text/plain)
Hosting options:
- Your existing web server
- Static hosting (GitHub Pages, Cloudflare Pages)
- Cloud storage with custom domain
Nginx Configuration
server {
listen 443 ssl http2;
server_name mta-sts.example.com;
ssl_certificate /etc/letsencrypt/live/mta-sts.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mta-sts.example.com/privkey.pem;
location /.well-known/mta-sts.txt {
root /var/www/mta-sts;
default_type text/plain;
}
# Redirect everything else
location / {
return 301 https://example.com$request_uri;
}
}
Then create the policy file:
sudo mkdir -p /var/www/mta-sts/.well-known
cat <<'EOF' | sudo tee /var/www/mta-sts/.well-known/mta-sts.txt
version: STSv1
mode: testing
mx: mail.example.com
mx: mail2.example.com
max_age: 86400
EOF
Apache Configuration
<VirtualHost *:443>
ServerName mta-sts.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/mta-sts.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mta-sts.example.com/privkey.pem
DocumentRoot /var/www/mta-sts
<Directory /var/www/mta-sts/.well-known>
ForceType text/plain
Require all granted
</Directory>
</VirtualHost>
Step 3: Create DNS Records
Add the MTA-STS DNS record:
_mta-sts.example.com. IN TXT "v=STSv1; id=20250117001"
The id field:
- Must change whenever policy changes
- Triggers senders to fetch updated policy
- Use timestamp or sequential version
Step 4: Implement TLS Reporting (Optional but Recommended)
Add SMTP TLS Reporting (RFC 8460) to receive failure reports:
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
Sample TLS report:
{
"organization-name": "Google Inc.",
"date-range": {
"start-datetime": "2025-01-17T00:00:00Z",
"end-datetime": "2025-01-17T23:59:59Z"
},
"policies": [{
"policy": {
"policy-type": "sts",
"policy-string": ["version: STSv1", "mode: enforce"],
"policy-domain": "example.com"
},
"summary": {
"total-successful-session-count": 1000,
"total-failure-session-count": 5
}
}]
}
Step 5: Verify Configuration
Test your setup:
# Check DNS record
dig +short TXT _mta-sts.example.com
# Check policy file
curl https://mta-sts.example.com/.well-known/mta-sts.txt
Use online validators:
- mxtoolbox.com/mta-sts.aspx
- hardenize.com
MTA-STS Best Practices
Follow these practices for successful implementation.
Start with Testing Mode
Gather data before enforcing:
version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
Monitor TLS reports for connection failures.
Ensure Valid Certificates
Certificate requirements:
- Valid (not expired)
- Trusted CA (not self-signed)
- Matches hostname
- Proper chain configured
Use Appropriate max_age
| Phase | Recommended max_age |
|---|---|
| Initial testing | 86400 (1 day) |
| Stable testing | 604800 (1 week) |
| Full enforcement | 1209600 (2 weeks) |
Short values during testing allow quick policy updates.
Update ID on Policy Changes
Always increment the DNS id when changing policy:
# Before change
_mta-sts.example.com. IN TXT "v=STSv1; id=20250117001"
# After change
_mta-sts.example.com. IN TXT "v=STSv1; id=20250118001"
Senders cache policies. Without ID change, they won't fetch updates.
Coordinate with Maintenance
If disabling TLS for maintenance:
- Update policy to
mode: none - Wait for
max_ageto expire (or use short max_age in advance) - Perform maintenance
- Re-enable policy
Monitor TLS Reports
Review reports for:
- Connection failure patterns
- Certificate problems
- Potential attack attempts
- Misconfigured sending servers
Complete Copy-Paste Setup Summary
Here are all the DNS records and files you need, in one place:
DNS Records
# MTA-STS announcement record
_mta-sts.example.com. IN TXT "v=STSv1; id=20260401001"
# TLS-RPT reporting record
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
Policy File (mta-sts.txt)
version: STSv1
mode: enforce
mx: mail.example.com
mx: mail2.example.com
max_age: 604800
Troubleshooting MTA-STS
When MTA-STS is not working as expected, use this table to diagnose and fix common issues:
| # | Problem | Symptom | Cause | Solution |
|---|---|---|---|---|
| 1 | Policy file not found | Sending servers ignore MTA-STS | Wrong URL path or missing .well-known directory | Verify file is at exactly https://mta-sts.example.com/.well-known/mta-sts.txt |
| 2 | Invalid SSL certificate | Senders report TLS handshake failure | Expired, self-signed, or hostname-mismatched certificate on mta-sts subdomain | Install a valid certificate from a trusted CA matching mta-sts.example.com |
| 3 | MX mismatch | Legitimate emails rejected in enforce mode | MX records in DNS differ from mx: entries in the policy file | Update the policy to list every MX hostname exactly as it appears in DNS |
| 4 | DNS record not resolving | MTA-STS not detected by senders | Typo in _mta-sts record name or record not published | Run dig +short TXT _mta-sts.example.com and verify the output |
| 5 | Stale cached policy | Senders enforce an old policy after changes | DNS id was not updated when the policy file changed | Always increment the id value when modifying the policy file |
| 6 | Wrong MIME type | Some senders fail to parse the policy | Web server serves text/html instead of text/plain | Add default_type text/plain (Nginx) or ForceType text/plain (Apache) |
| 7 | Emails bouncing after enabling enforce | Legitimate senders cannot deliver | Senders have TLS issues or your MX servers have certificate problems | Switch back to testing mode, review TLS-RPT reports, fix certificate issues, then re-enable |
| 8 | No TLS-RPT reports received | Cannot monitor MTA-STS effectiveness | Missing _smtp._tls DNS record or email address unreachable | Verify the TLS-RPT record exists and the rua mailbox accepts incoming email |
TLS-RPT Monitoring
TLS-RPT (RFC 8460) is the visibility layer for MTA-STS. Without it, you have no way to know if your policy is silently breaking email delivery.
How TLS-RPT Works
Sending mail servers that support TLS-RPT send daily aggregate reports in JSON format to the address specified in your _smtp._tls DNS record. These reports summarize TLS connection outcomes over the past 24 hours.
Full TLS-RPT Report Example
{
"organization-name": "Google Inc.",
"date-range": {
"start-datetime": "2026-03-31T00:00:00Z",
"end-datetime": "2026-03-31T23:59:59Z"
},
"contact-info": "smtp-tls-reporting@google.com",
"report-id": "2026-03-31T00:00:00Z_example.com",
"policies": [
{
"policy": {
"policy-type": "sts",
"policy-string": [
"version: STSv1",
"mode: enforce",
"mx: mail.example.com",
"mx: mail2.example.com",
"max_age: 604800"
],
"policy-domain": "example.com",
"mx-host": ["mail.example.com", "mail2.example.com"]
},
"summary": {
"total-successful-session-count": 4521,
"total-failure-session-count": 3
},
"failure-details": [
{
"result-type": "certificate-expired",
"sending-mta-ip": "198.51.100.42",
"receiving-mx-hostname": "mail2.example.com",
"receiving-ip": "203.0.113.25",
"failed-session-count": 3,
"additional-information": "Certificate expired 2026-03-28"
}
]
}
]
}
Key Metrics to Track
Monitor these metrics from your TLS-RPT reports:
- Success rate —
total-successful-session-count / (successful + failure). Target: above 99.9% - Failure count trend — A sudden spike indicates a certificate or configuration problem
- Failure types —
certificate-expired,certificate-not-trusted,starttls-not-supported,validation-failure - Affected MX hosts — Identifies which specific mail server has the problem
Setting Up TLS-RPT Processing
For small deployments, a dedicated mailbox and manual review works. For production environments, consider:
# Parse a TLS-RPT JSON report to extract failure details
cat tls-report.json | python3 -c "
import json, sys
report = json.load(sys.stdin)
for policy in report.get('policies', []):
total = policy['summary']['total-successful-session-count']
failed = policy['summary']['total-failure-session-count']
rate = total / (total + failed) * 100 if (total + failed) > 0 else 0
print(f\"Success rate: {rate:.2f}% ({total} ok, {failed} failed)\")
for f in policy.get('failure-details', []):
print(f\" FAILURE: {f['result-type']} on {f.get('receiving-mx-hostname', 'unknown')} ({f['failed-session-count']} sessions)\")
"
Conclusion
MTA-STS represents an important evolution in email transport security. It closes the gap left by opportunistic TLS encryption.
By declaring TLS requirements and specifying authorized mail servers, you protect against downgrade attacks and DNS spoofing.
Key takeaways:
- Start with testing mode
- Monitor TLS reports carefully
- Ensure certificates are always valid
- Update DNS ID when changing policy
Implementing MTA-STS positions your organization at the forefront of email security.
Related Guides
- HSTS Implementation Guide — Apply strict transport security for web alongside MTA-STS for email
- Email Authentication Monitoring — Monitor MTA-STS alongside SPF, DKIM, and DMARC
- TLS 1.2 vs TLS 1.3 Differences — Understand the TLS versions that MTA-STS enforces
- DMARC Policy Implementation — Complement MTA-STS with DMARC reporting and enforcement