Sending mail from your Home Lab using Office 365

A long time ago, I wrote a guide for sending automated mail from Ubuntu – those were simpler times where you only needed password based auth via smtp to send mail. Well, times have changed – SMTP password based auth will get deprecated at some point even for hosted Exchange. OAuth is better than simple password based auth as it better scopes access, makes it easier to invalidate or revoke etc.

Here’s how you can setup OAuth for Office 365 when you are using hosted Exchange on your own domain – the instructions can be adapted for consumer Office 365 accounts using outlook.com or hotmail.com.

Before we begin, a simplified understanding of OAuth: For OAuth, you need an Application that a user will sign into. This application will request permissions as part of the user sign-in. That in turn will allow the Application access to user data and act on the user’s behalf. On the sending side, typically Postfix is the MTA – Postfix does not understand OAuth nor does SASL. You need a plugin to SASL that will speak SASL auth on one side and OAuth on the other to establish an authenticated session that will allow postfix to send mail. At a high-level these are steps you need to complete:

  • Create and configure an Application for use with OAuth. The application should have Mail Send permissions.
  • Get an OAuth token for the Application and save it.
  • Install and configure a SASL OAuth Plugin.
  • Configure Postfix to use the SASL OAuth Plugin and provide it with the OAuth token to bootstrap the auth.

Create an Entra Application

  • Go to entra.microsoft.com. Login as admin for your domain.
  • Click on App Registrations > New Registration
  • In the app you created, Add permissions to the App – this just adds the list of permissions the app will request when a user signs into it. Click on API Permissions.
    • Add Office 365 Exchange Online > Mail.send (for hosted exchange)
    • Add Microsoft Graph > Mail.send (for regular accounts)
    • Make sure the “Admin Consent Required” is set to No.
    • To be safe, you may want to add the Offline Access permission
  • Click on Authentication (it says Authentication (preview) at the moment for me)
    • Click on Settings > Allow public client flows – make sure this is enabled
  • Note Directory (tenant) ID and Application (client) ID. This will be used when we configure the client-side authentication.
  • Ensure Hosted Exchange allows SMTP access for the user you want to send mail as:
    • Go to admin.cloud.microsoft > Users > Active Users > Mail User
    • Click on Mail tab > Email Apps. Make sure Authenticated SMTP is checked.

Get the OAuth Token

  • OAuth is an interactive protocol – the user needs to acknowledge and approve the sign-in at least once. After that token refresh can happen automatically.
    • We will use a Python script to sign-in to our Application as our mail send user and get the token.
    • This is best done on a machine where you have browser access – or at least have a browser handy.
    • First, setup the python venv for running the script – we use the msal library for the Outlook Auth:
      • Create a folder and copy https://github.com/ram-nat/sasl-oauth-rs/blob/main/scripts/sasl-xoauth2-tool
      • python3 -m venv venv
      • source venv/bin/activate
      • pip install msal
      • ./sasl-xoauth2-tool get-token outlook token.txt –client-id=<app-client-id> –tenant=<app-tenant-id>
      • When it prompts you to open https://microsoft.com/devicelogin and sign-in with the device code, do so. Make sure that you sign-in with the mail send user account. A safe approach would be to open the link in an incognito window so you are forced to sign-in and remember to use the right account.
      • If it works successfully, the token will be saved in token.txt.

Setup SASL OAuth Plugin

  • SASL is the standard authorization framework used by postfix. SASL does not natively support OAuth. However, it supports plugins.
    • You will need to install https://github.com/tarickb/sasl-xoauth2/ or alternately, I rewrote this in Rust (with a lot fewer features and likely some more bugs) here – https://github.com/ram-nat/sasl-oauth-rs
    • Install the plugin – use the packaged deb/rpm. Alternately, copy libsaslxoauth2.so to /usr/lib/x86_64-linux-gnu/sasl2/ (or equivalent folder for your distro).
    • Verify the plugin loads successfully – /usr/sbin/saslpluginviewer -c 2>/dev/null | grep -i xoauth2
    • Setup the oauth sasl plugin’s configuration – update or create /etc/sasl-xoauth2.conf with
{
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "",
  "token_endpoint": "https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token"
}

Configure Postfix to use SASL OAuth

# /etc/postfix/main.cf
relayhost = [smtp.office365.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options =
smtp_sasl_mechanism_filter = xoauth2
smtp_tls_security_level = encrypt
# /etc/postfix/sasl_passwd
# The "password" is the path to the token file
# Since typically postfix runs as chroot, this is path is relative to /var/spool/postfix or whatever the chroot root is
[smtp.office365.com]:587 [email protected]:/etc/tokens/[email protected]
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
sudo mkdir -p /var/spool/postfix/etc/tokens/
sudo chown postfix:postfix /var/spool/postfix/etc/tokens/
sudo chmod 700 /var/spool/postfix/etc/tokens/
# Copy the token file from the OAuth step to this folder as [email protected]

Make sure to update your header rewrites (through header_checks) and sender_canonical_maps are updated to match the mail send user correctly.

Attempt to send mail from your postfix server – if everything was setup correctly, you should see email send work!

Leave a Reply

Your email address will not be published. Required fields are marked *