- Published on
Setting up MTA-STS in Exchange Online
- Authors
- Name
- Jonathan Devere-Ellery
- What is MTA-STS?
- Implementing MTA-STS
- Creating an MTA-STS Record in DNS
- Hosting an MTA-STS Policy file
- Other resources
Microsoft announced back in February the general availability of SMTP MTA Strict Transport Security (MTA-STS) for emails in Exchange Online. This means that outbound emails from tenants are automatically protected using MTA-STS and with no configuration needed by administrators.
For inbound emails to Exchange Online however, this does require some additional configuration and is what we will explain in this article. To implement we need to publish two different components in order for remote email servers to ensure emails sent to Exchange Online and encrypted.
- Publish a TXT record in DNS
- Publish a Policy file specifying the MX records and TLS hostnames allowed to receive SMTP messages
What is MTA-STS?
First of all we should explain, what is MTA-STS, and why is it important?
Opportunistic TLS (STARTTLS)1 was created to better secure emails sent by SMTP, but this is still vulnerable to several different types of attacks.
Firstly, STARTTLS is completely optional so if an attacker can man-in-the-middle this connection process then they can effectively downgrade the security by stripping STARTTLS and preventing the negotiation of TLS encryption from succeeding, and the email to be sent in cleartext.
Secondly, an attacker could poison DNS responses and alter the MX responses for a domain, and cause sending email servers to connect to an attacker controlled SMTP server. The session would be encrypted, but email would be sent to an attacker-controlled server and certificate. SMTP does not include any way for a sending mail server to validate that an email is being sent to the correct SMTP server.
MTA-STS aims to be a simple way to validate that an email is being sent to the correct email server and that TLS is enforced. If the hostname of the receving SMTP server does not match the MX record published in the MTA-STS Policy file, or the server does not have a valid TLS certificate matching this hostname, then MTA-STS validation will fail and the sender will not send the email.
Implementing MTA-STS
Creating an MTA-STS Record in DNS
First we need to create a TXT
record in DNS which advertises to other email servers that MTA-STS is available for this domain. The domain will always be in the format of _mta-sts.<domain.tld>
This record should contain two different fields:
v=STSv1
which will always be the same value. Note that this is case-sensitive2id=
field which can contain any alphanumeric value up to 32 characters long, and should be update every time the MTA-STS policy is updated. For simplicity I'd recommend using a datestamp to indicate the last time it was updated.
To create a record in DNS using PowerShell we could use:
$STSRecord = "v=STSv1; id=$(Get-Date -UFormat +%Y%m%d%H%M%SZ)"
Add-DnsServerResourceRecord -Name "_mta-sts" -Txt -DescriptiveText $STSRecord -ZoneName "contoso.com"
Hosting an MTA-STS Policy file
Unlike Sender Authentication (SPF, DKIM, DMARC), MTA-STS is not done entirely through DNS records, and we also have to publish a policy file on a webserver at a specific URL. This policy will contain details of which enforcement mode, details of which MX records / TLS hostnames are allowed to receive emails, and how long the policy file should be cached.
The policy file always needs to be hosted at https://mta-sts.<domain.tld>/.well-known/mta-sts.txt
. Note that this is mta-sts.domain
needs to be an A
/AAAA
record in DNS. If you use a CNAME
record this will fail MTA-STS validation checks in Exchange Online.
Unfortunately it's not possible to host this file directly using Exchange Online, so a seperate solution needs to be used. If you already have an existing IIS or webserver for your organisation, then you can go ahead and use that, but in my case I don't have a webserver and the MTA-STS.txt file is only ~0.5kb. I don't want to create and manage a seperate webserver VM in my lab especially for such a tiny requirement.
Update (01/Oct/2022): I have written a Bicep template to automate the creation and configuration of an Azure Function App to host the mta-sts.txt file. If you are interested you can find the post at https://techobsessed.blog/blog/deploy-azure-function-app-using-bicep-for-mtasts/
There are other solutions for hosting this file, such as using GitHub Pages, but I decided on using Cloudflare Workers which fits my requirements nicely. By creating a Worker I can run Javascript code at the edge using the Cloudflare CDN, and use this to generate my static policy file.
From the Cloudflare Dashboard and Workers I created a new service. After creating the new service, clicking Quick Edit
allows me to enter the following code, and then Save and Deploy
the service.
async function handleRequest(request) {
const init = {
headers: {
'content-type': 'text/plain; charset=UTF-8',
'X-Clacks-Overhead': 'GNU Terry Pratchett',
},
}
return new Response(stsHTML, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
const stsHTML = `version: STSv1
mode: testing
mx: *.mail.protection.outlook.com
max_age: 86400
`
We also need to add some triggers to the service so that it will actually respond back on the URL that we need. We can achieve this by going under the Triggers heading, and adding a Route:
From here we can add a new route of *<domain.tld>/.well-known/mta-sts.txt
as a trigger for this service. We can also add multiple domains to all respond back with the same policy file if we want.
Now when we make a request to the https://mta-sts.contoso.com/.well-known/mta-sts.txt we get a text/plain2 response back with the following content:
version: STSv1
mode: testing
mx: *.mail.protection.outlook.com
max_age: 86400
If we have a TLS-RPT record configured in DNS, then we will start receiving reports of TLS usage when connecting on SMTP. We can use these reports to validate that our MTA-STS policy is working correctly. Once the validation is complete, we can change the policy mode from 'testing' to 'enforce' which actually begins protecting our domains. We should also increase the max_age value to a higher value to ensure that remote SMTP servers cache the policy for a longer period.
async function handleRequest(request) {
const init = {
headers: {
'content-type': 'text/plain;charset=UTF-8',
'X-Clacks-Overhead': 'GNU Terry Pratchett',
},
}
return new Response(stsHTML, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
const stsHTML = `version: STSv1
mode: enforce
mx: *.mail.protection.outlook.com
max_age: 604800
`
And that is it. We can continue to monitor the usage of TLS in SMTP by using TLS-RPT.
Hope that is helpful!
Other resources
- Enhancing mail flow with MTA-STS - Microsoft Docs - https://docs.microsoft.com/en-us/microsoft-365/compliance/enhancing-mail-flow-with-mta-sts
- MTA-STS validator - https://aykevl.nl/apps/mta-sts/