Microsoft Graph API SDK .NET Issues getting other users emails - microsoft-graph-api

I am using the Microsoft Graph SDK as downloaded from NuGet (1.2). I authenticate to Azure AD (using ADAL).
I am using Client Credentials flow (not authenticated as any particular user) and am using Application Permission roles to access resources.
We are going to set up one service mailbox with a bunch of aliases. The aliases are given to the clients. This is so they are emailing an address that has a meaningful name to them.
My app will run as a service, and routinely scan new emails in this inbox. It should find the To address, and depending on what alias was used, file the email in a location relevant to that client.
The resource I want is: GET /users/<id | userPrincipalName>/messages
However, there doesn't appear to be a method in the SDK for it.
I can get users with this:
IGraphServiceUsersCollectionPage filteredUsers =
graphApi.Users.Request()
.Filter("userPrincipalName eq 'user#domain.com'")
.GetAsync().Result;
When I loop through the collection, I can see that the User has a 'Messages' property, but it is always null.
If I manually build a request message with HttpClient I can get the messages.
The second problem is that the Recipient property is always the userPrincipalName of the mailbox. How can I get the alias that was used by the sender?

While you are able to get your collection of users successfully, you have to make another request to receive the messages. This would look something like:
IUserMessagesCollectionPage userMessages =
graphApi.Users["user_id"].Messages.Request()
.GetAsync().Result;
To answer your second question, at this time you cannot access the original recipient through the Graph API, but you can do this through EWS. This is due to the fact that you can only retrieve the SMTP message headers through EWS. You can read more about how to do this here.
If this is something you believe is valuable to you in the Graph, I would encourage you to post it in our UserVoice.
If you want to get the email as a file, you can simply get the body as bytes through the SDK:
byte[] asBytes = Encoding.Unicode.GetBytes(message.Body.ToString());

Related

Getting Meeting IDs from Events in an M365 Group

I've been tasked with a project to get attendance information from specific types of Teams. I have a service account that is already a member of these Teams, however it is unable to access an endpoint needed to resolve JoinWebUrls to meetingIDs (See example #3, 'Retrieve an online meeting by JoinWebUrl').
I have done the following thus far:
Create a new App Registration and assigning it 'OnlineMeetings.Read.All' as an Application permission (this process needs to run as a script, meaning that Delegate permissions won't work here)
Create a new Application Access Policy, assigned the aforementioned App Registration's App ID to it, and granted it to the service account.
Signed into MS Graph as the service account (using the 'password' grant_type) and retrieved the 'events' within the Team (via /v1.0/groups/$GroupID/events)
Extracted the JoinWebURL parameter from each of those events.
Step 5 would be to resolve the meetingID from the JoinWebURL, however when I all of the following requests fail:
GET /v1.0/me/onlineMeetings?$filter=JoinWebUrl eq '$JoinWebURL' (as the service account, which should be able to interact with the meeting)
GET /v1.0/users/$ServiceAccountObjectID/onlineMeetings?$filter=JoinWebUrl eq '$JoinWebURL' (as the service account to access it's own object's meetings, however this does seem to be the endpoint for Application permissions rather than Delegate permissions)
GET /v1.0/users/$ServiceAccountObjectID/onlineMeetings?$filter=JoinWebUrl eq '$JoinWebURL' (using the App Registration mentioned earlier, signing in with the 'client_credentials' grant_type)
GET /v1.0/me/onlineMeetings?$filter=JoinWebUrl eq '$JoinWebURL' (as the App Registration trying to access any meeting, however this does seem to be the endpoint for Delegate permissions rather than Application permissions)
Basically, I'm stuck. Is there something obvious that I'm missing? I'm also considering raising a support call with Microsoft, to see if the behaviour I'm experiencing is merely a bug.
Thanks in advance.
Events and online meetings are two different API's, you have created an event and trying to get online meeting details. That's the reason you are getting those errors. If you want to get event details please try this document.

Microsoft Graph API returns deleted objects

I'm using Microsoft Graph API to retrieve places using:
https://graph.microsoft.com/beta/places/{id}
or
https://graph.microsoft.com/beta/places/{id}
It successfully retrieves the place wanted.
If I remove the room using Remove-Mailbox (PowerShell cmdlet), Graph API request keeps retrieving the deleted room even after several hours.
Is this behavior by design ? How do I "refresh" data get by Graph API ?
Thanks
I see that you used Remove-mailbox cmdlet, but with which parameters you tried it? It matters a lot. For your scenario, I would suggest you to use the Identity and Permanent parameters to disconnect the mailbox from the user, remove the user account, and immediately remove the mailbox from the mailbox database. The mailbox doesn't remain in the mailbox database as a disconnected mailbox. Once you're done then give sometime for exchange to replicate the changes, then try make the above Graph API call, then see if it works or still you have the issue.
In case if you used Identity parameter alone to disconnect the mailbox from the user and remove the user account then, the mailbox still exists. It is retained until the deleted mailbox retention period expires - i think it happening in your scenario. The deleted mailbox retention period is controlled by the MailboxRetention property on the mailbox database or on the mailbox itself if the UseDatabaseRetentionDefaults property is False
You tried the same and confirmed that you used the "PermanentlyDelete" parameter and made sure it was not part of the "SoftDeleted" mailboxes anymore.

How should Slack bot tokens be stored?

I'm building my first Slack bot and I've got the basics mostly working... sending API requests, receiving commands and events, etc. But the part I'm left a bit confused about is what I'm supposed to do with the "Bot User OAuth Access Token".
The token appears to be shared across teams/workspaces, but it is returned to be during authentication of individual users with a call to /oauth.v2.access. Currently I'm storing the returned credentials payload in a table that has three columns:
My app's internal user ID
The Slack user ID embedded in the payload as authed_user.id
The entire JSON payload itself (jsonb in postgres if you're curious)
This allows me to initiate new API calls for actions that take place in my app (find by internal user ID) and also for interactions within Slack (find by Slack user ID).
What has left me a bit puzzled is what the convention is for when a user interacts with my bot that hasn't added my app. This can happen when a person ("Jose") adds my app and then their colleague ("Mary") discovers it in Slack and views the home screen, sends it a message, etc.
In order to take some action, such as prompt for the user to install my app, I need a token. Of course I have a token for Jose but not for Mary. I also have Jose's team ID stored in my table and Mary's team ID as part of the incoming event. So technically I could do something like this to get a working token to interact with Mary:
select credential_json from slack_credentials
where credential_json->>'type' = 'bot' and credential_json->'team'->>'id' = :marysTeamId
... which would pull out the bot token I captured when Jose added the app. This works, but it feels very wrong. I suppose if I just stored bot tokens in a separate table that looked like this:
The Slack team ID embedded in the payload as team.id
A subset of the JSON payload (ex: access_token, scope, bot_user_id, etc but not authed_user)
Then it wouldn't feel so yucky. But the docs + API ergonomics don't suggest this is a common approach either. So I'm curious what others do. If I don't hear anything back, I suppose my plan is to break out the bot tokens into a team-centric table.
Thanks!
The basic concept of Slack apps is that they are installed per workspace, not per user.
So while it's true that the app's token is derived from the user who installed your app to a new workspace, most the apps function are available to all users of the workspace.
e.g. slash commands will work for every user in every channel
e.g. posts of your app will be visible to all users of the related channel.
Therefore the best approach for storing tokens usually is with a primary key of Slack Team ID, Slack User ID.
And just to clarify. You do not need a token to prompt a user to install you app. Every app can be installed from webpage hosted by you (with the "Add to Slack button") or directly from the App Directory.

Microsoft Graph API get message returns empty string

I am querying to get a single message from the Microsoft graph API like the following:
https://graph.microsoft.com/v1.0/users/<name>/messages/<id>
However, i am getting a response that is just an empty string. If i make the same request using the beta version of the api like the following:
https://graph.microsoft.com/beta/users/<name>/messages/<id>
The email in question is a calendar share invitation of content-type of "application/ms-tnef" and content-class of "Sharing" in the email headers.
I can't find any documentation indicating this is a known issue in the system. Is there any way to get this to work in the graph API or is the only work-around is to use the beta version instead?
Using Graph Explorer, and recreating your request using their demo accounts returns a result in v1.0. I assumed by name you meant the user's email address and I made the same request using the Guid id of the user.
https://graph.microsoft.com/v1.0/users/MeganB#M365x214355.onmicrosoft.com/messages/AAMkAGVmMDEzMTM4LTZmYWUtNDdkNC1hMDZiLTU1OGY5OTZhYmY4OABGAAAAAAAiQ8W967B7TKBjgx9rVEURBwAiIsqMbYjsT5e-T7KzowPTAAAAAAEMAAAiIsqMbYjsT5e-T7KzowPTAAHi4GJzAAA=
https://graph.microsoft.com/v1.0/users/48d31887-5fad-4d73-a9f5-3c356e68a038/messages/AAMkAGVmMDEzMTM4LTZmYWUtNDdkNC1hMDZiLTU1OGY5OTZhYmY4OABGAAAAAAAiQ8W967B7TKBjgx9rVEURBwAiIsqMbYjsT5e-T7KzowPTAAAAAAEMAAAiIsqMbYjsT5e-T7KzowPTAAIgOnGGAAA=
Have you attempted the same request using graph explorer?

How do I add In-Reply-To and References to 'Send mail'?

My feature was built before /createReply existed and relies on:
Set a custom header with Outlook/Office 365 REST
to add References and In-Reply-To to an email. This allows the app to send email replies w/o requiring Mail.ReadWrite, which is much more access than we need:
https://learn.microsoft.com/en-us/graph/permissions-reference#mail-permissions
Read and write access to user mail
Allows the app to create, read, update, and delete email in user mailboxes. Does not include permission to send mail.
Now those headers no longer get added. (I also tried Cannot pass "In-Reply-To" parameter to Microsoft Graph sendMail and arrived at the same result as the author.)
Is there a way for me to get around this regression without requesting additional user permission? Thanks!
https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http
As of 2019-10-04, Microsoft published changes to their /reply endpoint which now allows for message:
https://learn.microsoft.com/en-us/graph/api/message-reply?view=graph-rest-1.0&tabs=http#request-body
https://github.com/microsoftgraph/microsoft-graph-docs/pull/5771
With the message field, I should be able to send replies w/o requesting additional permissions.

Resources