I am starting out in MS Graph. I have below code to pick up all mail messages from Inbox of a specific user. Then I go through each message, process it and set its Subject. When I try to save back message using UpdateAsync it executes fine but change in mail subject text doesn't seem to get saved.
What am I doing wrong?
Thanks
Regards
var inboxMessages = await graphClient
.Users[user.Id]
.MailFolders.Inbox
.Messages
.Request()
.OrderBy("receivedDateTime DESC")
.GetAsync();
foreach(Microsoft.Graph.Message x in inboxMessages) {
//Process message
// ...
x.Subject = "Processed: " + x.Subject
//Save changes to message Subject
await graphClient
.Users[user.Id]
.MailFolders.Inbox
.Messages[$"{x.Id}"]
.Request()
.UpdateAsync(x);
}
According to the documentation you can update Subject only for messages that have isDraft = true but not for those that have already been sent.
Related
I have the goal of being able to programmatically update OneNote page data using C#. The Microsoft Graph API reference documentation suggests this can only be done by page element, not by page, and gives the following C# Graph SDK example:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var stream = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(#"[
{
'target':'#para-id',
'action':'insert',
'position':'before',
'content':'<img src=""image-url-or-part-name"" alt=""image-alt-text"" />'
},
{
'target':'#list-id',
'action':'append',
'content':'<li>new-page-content</li>'
}
]
"));
var pages = new OnenotePage();
pages.Content = stream;
await graphClient.Me.Onenote.Pages["{onenotePage-id}"]
.Request()
.UpdateAsync(pages);
Below is the relevant snippet of my code:
GraphServiceClient client; // authenticated service client
CancellationToken cancellationToken; // a cancellation token
string userId; // identifier of user whose page contains the paragraph to be updated
string pageId; // identifier of page containing paragraph to be updated
string paragraphId; // identifier of paragraph to be updated
string filePath; // location of text file containing updated paragraph data
await client.Users[userId].Onenote.Pages[pageId]
.Request()
.UpdateAsync(new OnenotePage
{
Content = new MemoryStream(Encoding.UTF8.GetBytes(
// [
// {
// 'target':'{paragraphId}',
// 'action':'replace',
// 'content':'<p>{File.ReadAllText(filePath)}</p>'
// }
// ]
$"[{{'target':'{paragraphId}','action':'replace','content':'<p>{File.ReadAllText(filePath)}</p>'}}]"))
}, cancellationToken);
Microsoft's REST documentation includes PATCH /users/{id | userPrincipalName}/onenote/pages/{id}/content as a valid HTTP request, so my above code seems like it should work, even though it doesn't use the .Me option as in their example. For some reason, however, my code keeps throwing an InvalidOperationException, declaring that, "Timeouts are not supported on this stream," whenever it tries to execute the await command. Below are the details of the exception:
System.InvalidOperationException
HResult=0x80131509
Message=Timeouts are not supported on this stream.
Source=System.Private.CoreLib
StackTrace:
at System.IO.Stream.get_ReadTimeout()
When I try to run the raw REST command on the official Graph Explorer, I get a No Content - 204 message, confirming that the PATCH worked. Please note again, however, that I am instead simply using the C# MS Graph SDK.
Where am I going wrong? How can I accomplish my goal?
EDIT: I still don't have a solution to the SDK throwing InvalidOperationExceptions at me, and thus do not consider this matter resolved, but since the API seems to be working just fine, I went ahead and found a workaround to accomplish my goal. Posted here, in case anyone else encounters my same issue and needs something that works.
GraphServiceClient client; // authenticated service client
CancellationToken cancellationToken; // a cancellation token
string userId; // identifier of user whose page contains the paragraph to be updated
string pageId; // identifier of page containing paragraph to be updated
string paragraphId; // identifier of paragraph to be updated
string filePath; // location of text file containing updated paragraph data
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Patch,
client.Users[userId].Onenote.Pages[pageId].Content
.Request()
.RequestUrl)
{
Content = new StringContent(
// [
// {
// 'target':'{paragraphId}',
// 'action':'replace',
// 'content':'<p>{File.ReadAllText(filePath)}</p>'
// }
// ]
$"[{{'target':'{paragraphId}','action':'replace','content':'<p>{File.ReadAllText(filePath)}</p>'}}]",
Encoding.UTF8,
"application/json")
};
await client.AuthenticationProvider.AuthenticateRequestAsync(request);
await client.HttpProvider.SendAsync(request);
Email Not been recieved with attachments when I try to use Uploadsession using Graph API. can someone help me uderstand why this is happening. I have not recieved any error.
Message draft = await graphServiceClient.Users["UserID"].Messages.Request().AddAsync(email);
//Message draft = graphServiceClient.Users["UserID"].Mailfolders.Drafts.Messages.Request().AddAsync(email);
var stream = System.IO.File.Open(#"C:\attach\DYN28_6579332_33242556.csv", System.IO.FileMode.Open, FileAccess.Read, FileShare.None);
var attachmentItem = new AttachmentItem
{
AttachmentType = AttachmentType.File,
Name = "DYN28_6579332_33242556.csv",
Size = stream.Length
};
var uploadSession = await graphServiceClient.Users["Userid"].Messages[draft.Id]
.Attachments
.CreateUploadSession(attachmentItem)
.Request()
.PostAsync();
var maxSlicesize = 320 * 1024;
var largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, stream, maxSlicesize);
IProgress<long> progress = new Progress<long>(prog => {
Console.WriteLine($"Uploaded {prog} bytes of {stream.Length} bytes");
});
// Upload the file
var uploadResult = await largeFileUploadTask.UploadAsync(progress);
if (uploadResult.UploadSucceeded)
{
// The ItemResponse object in the result represents the
// created item.
//Console.WriteLine($"Upload complete, item ID: {uploadResult.ItemResponse.Id}");
Console.WriteLine("upload completed");
}
Finally sending email with
await graphServiceClient.Users["userid"].Messages[draft.Id]
.Send()
.Request()
.PostAsync();
There is a limit of 4MB on a single request in the Graph API. To send larger attachments, you need to first create an upload session against the email message/calendar event, and upload your attachment in a number of requests as part of this session. AFAIK each of the smaller POST requests would also need to stay below the 4MB limit.
You can find more detailed documentation and a sample walkthrough here.
POST https://graph.microsoft.com/v1.0/me/messages/AAMkADI5MAAIT3drCAAA=/attachments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
I have created an event in the outlook calendar. The event contains Teams join link.
While I am updating the event from MS Graph API, the join button is being removed.
Here is the sample code of what I am doing:
void UpdateEventInCalendar(string eventId)
{
var getCalEvent = Task.Run(() =>
{
return service.Me.Events[eventId].Request().GetAsync();
});
Task.WaitAll(getCalEvent);
BodyType bodyType = BodyType.Text;
Event eventToUpdate = getCalEvent.Result;
Event updatedEvent = new Event();
updatedEvent.Id = eventToUpdate.Id;
updatedEvent.Subject = "Updated text";
updatedEvent.ShowAs = eventToUpdate.ShowAs;
updatedEvent.Body = new ItemBody
{
ContentType = bodyType,
Content = "Some new content"
};
graphServiceClient.Me.Events[updatedEvent.Id].Request().UpdateAsync(updatedEvent.Id);
}
Event before update:
Event update content:
Event after update:
How to keep the event while updating the event?
As a workaround you can try this to keep your online meeting appeared:
First: in your addEvent function, your body should be like this
AddedEvent.Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p id = 'MsgContent'>Your Body</p>"
};
Second: In the update event, you can change the body content like this
HtmlDocument html = new HtmlDocument();
html.LoadHtml(EventToUpdate.Body.Content);
html.GetElementbyId("Msgcontent").InnerHtml = "Your new body";
updatedEvent.Body = EventToUpdate.Body;
updatedEvent.Body.Content = html.DocumentNode.OuterHtml;
Try not updating the body and you will be able to make it work. See this thread. Yes, if you update the body without isonlinemeeting, the teams meeting blob will be removed and this makes the isonlinemeeting property to false and we are loosing the button.
I faced the same issue and I got out with this solution, hope it helps.
You create an online event through the API with an empty body. The response from the server contains the HTML body with the join link and you store it. Then, if you update the event preserving all the online meeting related content, the event keeps having the join button, so you get the needed result.
If you update the event body deleting the online meeting related content, you loose the join button and, according to the docs, there's not much you can do about it.
I am trying to use delta query to get the changes in one of the rooms calendars, when i use the start date and end date to set the initial request, it returns the correct events data and then afterwards when I use the delta token next time to make request, but it returns event data with tag saying this particular event has been deleted and does not return any valuable info apart form ID.
Here is my code
private async Task<IEventDeltaCollectionPage> GetEventData(GraphServiceClient graphClient, object deltaLink)
{
IEventDeltaCollectionPage page;
if (lastPage == null)
{
var queryOptions = new List<QueryOption>();
if (deltaLink == null)
{
queryOptions = new List<QueryOption>()
{
new QueryOption("startdatetime", "2020-01-16T00:00:00Z"),
new QueryOption("enddatetime", "2020-01-24T00:00:00Z")
};
}
else
{
queryOptions = new List<QueryOption>()
{
new QueryOption("$deltatoken", deltaLink.ToString())
};
}
page = await graphClient
.Users["nitroom2#domain.onmicrosoft.com"].CalendarView
.Delta()
.Request(queryOptions)
.GetAsync();
}
else
{
lastPage.InitializeNextPageRequest(graphClient, deltaLink.ToString());
page = await lastPage.NextPageRequest.GetAsync();
}
lastPage = page;
return page;
}
AS you can see this code will either look for dates range or delta token. so what I do is I initially make a call without a delta token, then once I get the final response I get the delta token. I restart the application this time and I provide the hard-coded delta token. Before restarting the application I also make sure that there is either a new event created or updated in the rooms calendar and then I restart the application with the delta token. I get a response back with some event data but that's telling me the event has been deleted, but that's not true.
Not sure what i am misisng here. can any abody suggest?
when using delta query Microsoft Graph returns as deleted new/updated/deleted items that are not in start-end date range of the initial request.
please check if that was your case :)
When I GET https://graph.microsoft.com/v1.0/me/messages, it returns messages I received in MS Teams.
How can I query for only emails using the MS Graph API?
As AAvery said, I believe as well that Teams send you the messages to your Outlook after a while of inactivity. Try to remove those emails(notifications) from MS Teams and try to GET again.
Eventually, try this: https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages/delta
I came here to ask same question but I was able to get some clue which helped me to get my code working.
my old code:
public async void ReadMails(IAuthenticationProvider authProvider)
{
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var messages = await graphClient.Me.Messages
.Request()
.Select(e => new
{
e.Sender,
e.Subject,
e.Body
})
.GetAsync();
}
New code code which reads only emails now.
public async void ReadMails(IAuthenticationProvider authProvider)
{
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var messages = await graphClient.Me.MailFolders.Inbox.Messages
.Request()
.Select(e => new
{
e.Sender,
e.Subject,
e.Body
})
.GetAsync();
}
I hope this helps.