Sending "free" emails through Microsoft (Office?) 365
This was a HUGE pain to figure out, and I, uh, didn't originally write it down, so
3 min read
Background
So I've recently been needing to send emails, and, well, mail services are EXPENSIVE! $40 a month!?! Yikes!
Turns out though, I pay for Office 365 ($8 a month!) for my email, and I thought "well can I send emails through Office?" The answer is yes! But it wasn't straightforward.
First, I spent days trying to get SMTP relay and stuff to work only to find some weird errors in Office, and that Hetzner blocks port 25! Agh!
Then, I learned about Microsoft Graph, their HTTP API that let's you send emails! Turns out, it's even more free than SMTP.
With SMTP, you need to pay a full Exchange subscription for every identity, but with Microsoft Graph you can send from shared mailboxes, which are free!
How to set up
We start in the Microsoft admin dashboard (https://admin.microsoft.com). If you navigate to "Teams & groups", then "Shared mailboxes", you can create your shared mailbox. Once done, be sure to open the user and grab the ID from the URL (we'll need it later!).
Next, we open the Identity/Entra dashboard. In your left sidebar, click "Show all," then select "Identity" and sign in with the same tenant.
Once there, navigate to "Enterprise applications" (under applications) and click "New application".
Once here, click "Create your own application", then give it a name and save.
Once it's completed, navigate to "App registrations" (right below "Enterprise applications"). If you don't see your app, then click "View all applications in the directory".
Open the app and make sure to save your client and tenant IDs from it's overview page (we'll need them later!), then select "API permissions" from it's sidebar.
Click "Add a permission", then "Microsoft Graph", then "Application permissions".
Scroll down to Mail, select the Mail.Send permission, then hit "Add permissions".
Now, Microsoft needs admin consent so hit "Grant admin consent" on the API permissions page.
Aaaaaaaaaaand we're done! Time to write the code!
The code
The code for this is very simple, we have a two step process; get our access token, then send the email.
Access token
Make a URL-encoded (form) POST request to https://login.microsoftonline.com/YOUR_TENANT_ID_HERE/oauth2/v2.0/token
with the following fields in the body:
-
grant_type=client_credentials
-
scope=https://graph.microsoft.com/.default
-
client_id=YOUR_CLIENT_ID_HERE
client_secret=YOUR_CLIENT_SECRET_HERE
Our access token will be in the JSON body of the response with the keyaccess_token
. Our response also contains anexpires_in
field that tells gives us the time in seconds until the token expires (i.e. 30 means it expires in 30 seconds).
Send the email
Sending the email is also very straightforward, we make a JSON encoded POST request to https://graph.microsoft.com/v1.0/users/YOUR_SHARED_MAILBOX_ID_HERE/sendMail
with fields in the body as described here. I'd write em all out, but that's kinda unnecessary when Microsoft did it for me!
Conclusion
Overall, despite all the pain, this was worth it! I'm saving $40 a month on the handful of emails I do send. However, be aware that Office is not designed for use like this, so there are some rate limits you will run into when you try to scale up. Luckily, I'm not there yet!
Happy coding!