Check email on O365 with OAuth

Does anyone know the best way to approach collecting email from O365 email accounts using Lucee?

Up until recently this has been simple by using cfpop or cfimap, which connects using Basic Authentication. However, MS are now disabling basic authentication, and seem to want to force us to use OAuth. Any ideas how we might go about this?

@mikep I think you have to create an App password for your email account and use the app password instead of the original password in the cfpop/cfimap tag

1 Like

I just converted a couple cfimap processes for a client using MS Office 365. You can use Oath and a client app secret to authenticate to the Graph API. I’ll see about sharing some code when I get in the office later.

This sounds like just the thing. It would be great to see how you do it, thanks.

CFIMAPOauth.cfc (11.3 KB)

OK, I had to rip a bunch of client-specific stuff out so apologies if I left any syntax errors, etc. This is the basic CFC I used to replace my client’s use of CFIMAP in their application. It only implemented what I needed, so it may or may not do what you need. This is what id does

  • Downloads messages for a given user
  • max records
  • saves attachments with unique names in a folder of your choice with some filename cleanup
  • returns the same query object that cfimap created so you can hopefully just drop it in
  • deletes a single message by ID (passed as a new column called graphID)

So in order to use this you need to log into your Azure console and create a new oauth application with a similar flow to creating a facebook or twitter app. But unlike the typical Oauth flow used for SSO where a human user bounces through MFA, you set up an application using “client credentials”. This app will be able to read the E-mails of any user, but you’ll need to assign those permissions to the app.
Here’s a link to help with that part:

Once you’ve set up your app

  • enter your tendant ID into the CFC
  • enter your client ID to the CFC
  • provide your client secret as an env var or java system prop. You can hardcode it into the CFC but I DON’T RECOMMAND IT since it’s like a super powerful password which would give anyone access to every E-mail address in your tenant.

There are a few other assumptions my CFC makes

  • it will be created by WireBox
  • you will have the Hyper module also installed
  • Logbox will be available (comes via WireBox)

If you aren’t using those, that’s a darn shame, but you can easily refactor the code to work around it.

  • Manually create the CFC and place it in the application scope to make it a singleton
  • manually call the onDIComplete method once after creation to generate the initial access token
  • Replace the Hyper calls with naked CFHTTP calls and do the work of deserializing the JSON yourself
  • Replace the LogBox calls with some sort of manual logging

It’s also worth noting, there’s nothing preventing you from using an access token from a single sign on flow here if you are making a physical human go through the SSO flow and generate their own token. You’d need to rework the auth flow, but all the actual GraphAPI calls would work the same so long as that user’s token had the correct permissions.

Good luck!

1 Like

And just for funsies-- if you want to use S3 for storing the attachments, as I’m actually doing for my client, you can use the S3SDK and swap out the filewrite() stuff with this

s3sdk.putObject(
    data = toBinary( a.contentBytes ),
    uri = 'emailAttachments/' & a.name,
    contentType = a.contentType
);

Thank you so much Brad, this is fabulously helpful. Although we don’t use wirebox I expect we can modify it according to our needs. Hopefully we’ll get time to work on this during this coming week and I’ll feed back how we got on.

1 Like