Graph API Mail.Send Issue

Hi,

I am configuring the Microsoft Graph API to enable me to send emails on users behalf, so far i have for O’Auth working properly, and my API structure works:

{
“message”: {
“subject”: “<Subject_Text>”,
“body”: {
“contentType”: “HTML”,
“content”: “<Body_Content_HTML>”
},
“toRecipients”: [
<To_JSON>
],
“ccRecipients”: [
<CC_Recipient_Email>
],
“bccRecipients”: [
<BCC_Recipient_Email>
]

},
“saveToSentItems”: “true”
}

I am able to sucessfully initialise this with Graph API, and it will send the email, below are my test values:

I am also able to trigger this from my workflow. My To list is being populate from a little group i have built below:

This forms the basis of the workflow, which sets the email addresses in a to, cc and bcc list. Each item is formatted like below:

The issue i am facing is that if one of the fields is not populated. e.g the user does not copy or bcc anyone in, then this all breaks and the email will not send. The reason for this, i suspect is that Bubble is sending a ‘null value’ see below:

Now at the moment, the cc and bcc field can be blank (configured in the API workflow) so if this is empty. It just sends Null, which the Graph API won’t accept. If i check this box so that a value must be entered, it will just use the test value in the API connector, which is not what i want. I tried changing the test value in the API connector to nothing or but then of course the API won’t actually initialise, i also tried to use bollean formatting in workflow like below:

But this still does not work, i think probably because i am formatting the cc-list, and that is actually empty, since the user did not add anyone to the CC field.

So basically i am really stuck and cannot see how i can somehow force a value that Graph will accept without returning null.

I hope this make sense, if anyone is able to help, i would be very grateful!

Thanks

You don’t need to have a formatted as text ( as terniary operators). You already have the square bracket in your JSON format. So if the list is empty, this will be sent as [ ] an empty array.

Actually, adding square bracket again will broke your json.

Be sure that the API doesn’t request you to send null (in most case, empty array is fine however). If this is the case, at this moment you will need to use formatted as text

one workaround that works for me with graph api is to completely remove the ccRecipients and bccRecipients keys from the json when they are empty instead of sending them as null or empty array.

you can do this by creating different api calls - one with all fields, one with just to and cc, one with just to. then use conditional logic in your workflow to pick which one to call based on what fields have values.

its not the cleanest solution but graph api can be picky about null values in the request body.

Thanks for this, managed to get round it via a Boolean formatting, so I did not have to build different workflows, but fiddly though. One more question, how have you managed with user agent flow, I keep having to refresh the tokens every hour! Apparently Graph does not issue refresh tokens for user agent/implicit flows? Any experience with this?

For me, it consistently sent a null value into the API. The first thing I did was try this but could not get it to work, can send screenshots tomorrow.

If you don’t mind, can I ask about user agent flow, my tokens have to be refreshed manually every hour, and my understanding is that Graph will not issue tokens for user agent flow. I did see offline in scope.

Cheers.

Yes it will if you add scopes offline_access to your request. This is the only way to get a refresh token.

Also, Keep in mind that API Connector doesn’t refresh token. It’s only for run mode / real users.

If this is not the case, report this as a bug.

For the “null” issue sent, remove “Allow blank” in api connector. This is why Bubble send [ null ] instead of empty array.

What do you mean by the above? I have only recently started using the API connector so I am a bit new to it. If Graph don’t support issuing refresh tokens via this method, then surely bubble can’t refresh them? At the moment I have to re-authenticate the keys every 60mins, and when I am previewing the app as a user, it will just stop processing the calls without warning the user to log back in or anything.

Graph support it. You need to add offline_access to your scopes list in user-agent

What I mean is that API Connector itself will never refresh the token. The refresh token is only applied for real user of your app that authenticated with this method.

Hi Jici,

Thanks for this, but i do have offline_access in the API scope.

I have also logged in as a real user, but still the tokens only last for 1 hour. Have you managed to set this up yourself and not have to refresh tokens?

Whilst i know other API’s do allow refresh tokens through user agent flow, my understanding is that Graph do not, see below:

  • Short-lived Access Tokens: The access tokens issued through the user-agent flow have a short lifespan, typically around one hour.

  • Silent Renewal: To obtain new tokens without user interaction, the recommended practice is to use a hidden iframe or similar silent request method with the prompt=none parameter. The Microsoft Authentication Library (MSAL.js) handles this process automatically for you via methods like acquireTokenSilent.

  • User Re-authentication: If the silent renewal fails (e.g., due to revoked permissions or an expired session), the user will need to interactively sign in again to acquire a new set of tokens.

If your application requires long-lived access to Microsoft Graph without the user being present, you should use a different authentication flow that supports refresh tokens, such as the authorization code flow.

My understanding based on this is that i would need to move away from user agent flow, to achieve this?

Can you share your API connector auth setting? Yes I did a long time ago. Not excluded that it could be a Bubble bug.

For the doc you shared, your forget to share the scopes part and the token response part that both show that a refresh token will be issued if you set the offline_access scope. When API use refresh token, access token are always short lived. This is not different VS Google for example.

One question however:is it how your users login into your app or you have a email/password Bubble native auth and you are trying to add oauth2 to the authenticated user account?

I just use native bubble at the moment, i might allow sign in through Google/MS. but the primary reason for integrating with Graph, was because i am building a CRM and it allows users to email from the system, as a result i wanted to use the mail.send function in the graph API. As you can imagine, having a user have to keep signing in every hour is just not a workable solution, whilst i was aware that the user agent flow does give short-term tokens, i did imagine that as long as offline_scope was defined in the API, the tokens would refresh, But the more i look into it, the more i seem to think Graph ignores the offline_scope because it is an implicit flow which i don’t think they deem as secure enough to issue refresh tokens.

Gemini and ChatGPT give different responses, but both seem to think building a custom process might be achievable, Graph does support refresh but i believe you have to use PKCE (I dont know much about this at all) but i don’t think Bubble supports it.

I just don’t really see the point of this user agent flow Bubble has built if it will not handle the refresh tokens, unless this is just a Graph specific thing.

Appreciate your comments, let me know what you think.

So your issue may be there. If your user log in with email password and after you are trying to add the user-agent to this logged in user, you may face some issue. Technically, Bubble replace auth of this user with the data from oAuth2, but I guess that is user log in again with email and password, this may void the oAuth2 data and Bubble will not refresh it. You could also have a bug if the user token is not refreshed if the user stay logged in with the oAuth provider but the user was created with email/password Bubble native auth. Do test: log out and log in with social network with a new account and check if you are facing the same issue.

If you want to keep the email/password Bubble auth, you will need instead to use the manual oauth2 process like described here: https://forum.bubble.io/t/showcase-manual-oauth2-token-integration/79988/

Hi Jici,

I will test what you suggested tomorrow. Thanks very much for your link regarding the custom Auth flow, I think it your suggestion does not work I will need to try and build this.

I also see Pathfix as a potential solution to remove the headache of this token refresh, not sure if you have any experience with this and would recommend?

Thanks again for your assistance.

Rob

Pathfix is not a bad solution but maybe not needed. For me, I don’t see any value, but for someone that is less familiar with handling manual auth process, this could help for sure.

Yes appreciate what you’re saying. I have tried to not use much in the way of third party services, but I’m getting pretty sick of this token refresh situation. Will look at the resources you sent over and see how easy it is!

1 Like