Server — Mail — MTA-STS
The Postfix TLS article configured TLS correctly on February’s end. MTA-STS, Mail Transfer Agent Strict Transport Security, is the mechanism that tells the rest of the internet to use it. Without MTA-STS, a sending server could silently downgrade from TLS to plaintext during an active attack, even if February is perfectly configured to accept TLS. MTA-STS closes that gap by publishing a policy that says: only deliver to this server over TLS, and verify the certificate.
MTA-STS has two sides and both need configuring:
Publishing your own policy tells other servers how to deliver mail to February. This involves a policy file served over HTTPS and a DNS record pointing to it.
Honouring other domains’ policies tells February to check and enforce MTA-STS policies when it delivers outbound mail. This requires the postfix-mta-sts-resolver daemon backed by Redis.
How MTA-STS works
When a mail server is about to deliver a message to yourdomain.com, it can optionally check whether that domain publishes an MTA-STS policy. It does this by querying a DNS TXT record at _mta-sts.yourdomain.com and fetching a policy file from https://mta-sts.yourdomain.com/.well-known/mta-sts.txt.
The policy file specifies the mode (testing, enforce, or none), the maximum age the policy should be cached, and the permitted MX hostnames. If the policy mode is enforce, the sending server must connect over TLS and verify that the certificate matches one of the listed MX hosts. If TLS cannot be established or the certificate does not match, delivery fails rather than falling back to plaintext.
The HTTPS requirement for the policy file is deliberate: it means the policy itself is authenticated. An attacker who can tamper with DNS cannot serve a false policy, because they cannot also forge a valid HTTPS certificate for mta-sts.yourdomain.com.
Part one: publishing your policy
Prerequisites
The policy file must be served over HTTPS from mta-sts.yourdomain.com. This requires:
A publicly trusted TLS certificate for mta-sts.yourdomain.com. A self-signed certificate will not work here: the receiving mail server must be able to verify it against a public CA. Let’s Encrypt is the practical choice.
An HTTPS server accessible on the public internet. This article uses Nginx, which will be covered more fully in the reverse proxy sub-series. A minimal Nginx configuration sufficient for MTA-STS is included here.
If a Let’s Encrypt certificate is not yet available for February’s domain, either obtain one before configuring MTA-STS, or start in testing mode rather than enforce mode while the certificate is arranged.
The policy file
Create the directory and file:
sudo mkdir -p /var/www/mta-sts/.well-known
sudo nano /var/www/mta-sts/.well-known/mta-sts.txt
version: STSv1
mode: enforce
max_age: 2419200
mx: mail.yourdomain.com
The fields:
mode: enforce — sending servers must use TLS and verify the certificate. Start with mode: testing if you are not yet confident the TLS configuration is correct. In testing mode, sending servers fetch and check the policy but do not enforce it; failures are reported via TLSRPT (covered in the next article) rather than causing delivery failures.
max_age: 2419200 — 28 days in seconds. Sending servers cache the policy for this duration. A shorter value means more frequent lookups but faster propagation when the policy changes. A longer value reduces lookup traffic but means a policy change takes longer to propagate.
mx: mail.yourdomain.com — the permitted MX hostname. This must match the certificate common name or a SAN on February’s mail certificate. Add one mx: line per permitted MX host if there are multiple.
Set ownership:
sudo chown -R www-data:www-data /var/www/mta-sts
Nginx configuration for the policy file
Install Nginx if not already present:
sudo apt install nginx
Create a minimal virtual host at /etc/nginx/sites-available/mta-sts:
server {
listen 80;
server_name mta-sts.yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name mta-sts.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/mta-sts.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mta-sts.yourdomain.com/privkey.pem;
root /var/www/mta-sts;
location /.well-known/mta-sts.txt {
default_type text/plain;
add_header Cache-Control "max-age=86400";
}
location / {
return 404;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/mta-sts /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Obtain a Let’s Encrypt certificate for the subdomain:
sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d mta-sts.yourdomain.com
After obtaining the certificate, reload Nginx and verify the policy file is accessible:
curl -s https://mta-sts.yourdomain.com/.well-known/mta-sts.txt
The output should match the file content exactly.
The DNS records
Two DNS records are needed. Both go into PowerDNS.
The _mta-sts TXT record signals that a policy exists and includes a policy ID:
sudo pdnsutil add-record yourdomain.com _mta-sts TXT 3600 "v=STSv1; id=20260512120000"
The id value is an arbitrary string that changes whenever the policy changes. Using a timestamp in the format YYYYMMDDHHMMSS is conventional. Sending servers compare the cached policy ID with the current one; a mismatch triggers a fresh policy fetch.
Update the ID whenever the policy file changes. If the ID stays the same, sending servers use their cached copy and do not see the update until it expires.
The TLSRPT DNS record enables TLS reporting (covered in the next article). It is worth adding now alongside the MTA-STS record:
sudo pdnsutil add-record yourdomain.com _smtp._tls TXT 3600 "v=TLSRPTv1; rua=mailto:tls-reports@yourdomain.com"
Rectify the zone:
sudo pdnsutil zone rectify yourdomain.com
Verify both records:
dig TXT _mta-sts.yourdomain.com @127.0.0.1
dig TXT _smtp._tls.yourdomain.com @127.0.0.1
Part two: honouring other domains’ policies
Publishing a policy tells other servers to use TLS when delivering to February. Honouring policies means February checks and enforces other domains’ MTA-STS policies when it sends outbound mail. This is the more complex half and requires additional software.
postfix-mta-sts-resolver
postfix-mta-sts-resolver is a daemon that Postfix queries via a socketmap. When Postfix is about to connect to a remote mail server, it asks the daemon whether that server has an MTA-STS policy. If so, the daemon returns the required TLS policy, and Postfix enforces it.
The daemon caches fetched policies in Redis. Since February already has Valkey running (which is compatible with Redis clients), this dependency is already satisfied.
Install the resolver:
sudo apt install postfix-mta-sts-resolver
Configure it at /etc/mta-sts-daemon.yml:
host: 127.0.0.1
port: 8461
reuse_port: true
shutdown_timeout: 20
cache:
type: redis
options:
address: "redis://127.0.0.1:6379/1"
db: 1
default_zone:
strict_testing: false
timeout: 4
zones:
myzone:
strict_testing: false
timeout: 4
The Redis address uses database 1 to keep MTA-STS cache data separate from other Redis data. Adjust if Valkey is listening on a non-default port.
Enable and start the daemon:
sudo systemctl enable --now postfix-mta-sts-resolver
sudo systemctl status postfix-mta-sts-resolver
Connecting Postfix to the resolver
Add to /etc/postfix/main.cf:
# MTA-STS policy enforcement
smtp_tls_policy_maps = socketmap:inet:127.0.0.1:8461:postfix
This tells Postfix to query the resolver for TLS policy information before connecting to remote servers. The resolver returns the appropriate policy based on whether the destination domain publishes MTA-STS.
Reload Postfix:
sudo postfix check
sudo systemctl reload postfix
Testing the resolver
Query the resolver directly for a domain known to publish MTA-STS:
/usr/bin/mta-sts-query gmail.com smtp.gmail.com
A successful response shows the Gmail MTA-STS policy, including the mode and the list of permitted MX hosts. If the query times out or returns an error, check that the resolver is running and that Redis is accessible on the configured address.
Test that Postfix picks up the policy by sending a message to a Gmail address and checking the mail log:
sudo tail -f /var/log/mail.log | grep -E "TLS|STS|mta-sts"
Since February uses Fastmail as its relay, the MTA-STS resolver’s impact on outbound mail is mainly relevant if February ever sends directly. But having the resolver in place means it operates correctly from the start.
Policy mode progression
The recommended approach for a new MTA-STS deployment:
Start with mode: testing while verifying the TLS configuration and collecting TLSRPT reports. In testing mode, delivery is never blocked; only reports are generated.
Switch to mode: enforce once TLSRPT reports confirm that no legitimate delivery paths are being flagged for TLS failures. Update the policy ID when changing the mode.
Set a long max_age once the policy is stable. Longer cache durations reduce DNS and HTTPS lookup overhead at the cost of slower propagation when the policy changes.
Updating the policy
When any aspect of the policy changes — the mode, the MX hostnames, the certificate — update both the policy file and the DNS record’s id value:
sudo nano /var/www/mta-sts/.well-known/mta-sts.txt
# Edit as needed
sudo pdnsutil replace-rrset yourdomain.com _mta-sts TXT 3600 "v=STSv1; id=$(date +%Y%m%d%H%M%S)"
sudo pdnsutil zone rectify yourdomain.com
The replace-rrset command replaces the existing TXT record rather than adding a second one.
What MTA-STS achieves
With the policy published and the resolver active, February’s mail setup is protected against SMTP downgrade attacks in both directions. A network-level attacker who strips STARTTLS from an inbound connection to February will find that sending servers with MTA-STS support refuse to deliver without TLS. February itself will refuse to deliver to domains that publish MTA-STS enforce policies without a valid TLS connection.
Neither protection is absolute — MTA-STS only helps when the sending server supports it, and not every mail server does — but it covers the major providers and is the current best practice for SMTP transport security.
The TLSRPT article that follows covers the reporting side: getting notified when TLS failures occur, which is how you confirm the policy is working and catch any legitimate delivery paths that need attention.