Download .eml file with Microsoft Graph C# - c#

I have some problem with Microsoft Graph.I would like to download the attachments present in a specific email. I have verified that the type of object returned after this:
var attachments = graphClient.Me.Messages[msg.Id].Attachments.Request().GetAsync().Result;
foreach(var item in attachments) {
var current_attachment = graphClient.Me.Messages[msg.Id].Attachments[item.Id].Request().GetAsync().Result;
}
is an object of type Attachment.
Now, I would like to download this object (current_attachment) but I saw that the property ContentBytes isn't available.
I have tried to cast the object to FileAttachment, but it throw an exception.
Thank you.

This should be fairly straightforward. Specifically:
https://learn.microsoft.com/en-us/graph/outlook-get-mime-message
Even though Outlook does not save messages in MIME format, there are
two ways you can get an Outlook message body in MIME format:
You can append a $value segment to a get-message operation on that
message. If the message is attached to an Outlook item or group post,
you can append a $value segment to a get-attachment operation on that
item or group post. In either case, your app must have the appropriate
permissions to access the Outlook item or group post in order to apply
the get-message or get-attachment operation.
You can then save the message body content in a .EML file and attach
the file to records in business systems, such as those for CRM, ERP,
and bug tracking.
Here is an example:
https://learn.microsoft.com/en-us/graph/api/message-get?view=graph-rest-1.0&tabs=csharp
Gets the MIME content of a message in the signed-in user's mailbox.
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var stream = await graphClient.Me.Messages["4aade2547798441eab5188a7a2436bc1"].Content
.Request()
.GetAsync();
You can write "stream" to a disk file like this:
string path = #"\my\path\myfile.eml";
using(FileStream outputFileStream = new FileStream(path, FileMode.Create))
{
stream.CopyTo(outputFileStream);
}
The resulting .eml file will be the complete email, including all attachments.

You can do a similar call to get an InputStream for the ItemAttachment as you would do to get the InputStream for a Message.
See code below in java but will be similar for c#. The java API is missing the .content() option on Attachments but you can build the url and append $value instead.
URL requestUrl = graphClient.users("user#***.com").messages("*****").attachments("****").buildRequest().getRequestUrl();
InputStream is = new FileAttachmentStreamRequestBuilder(requestUrl.toString() + "/$value", graphClient, null).buildRequest().get();
// save the file
Files.copy(is, Paths.get(fileName + extension), StandardCopyOption.REPLACE_EXISTING);

Related

How to add an attachment to a loaded MimeMessage (MimeKit) [duplicate]

This question already has answers here:
MimeKit add attachments to a message loaded from mht file
(2 answers)
Closed last month.
Is there any general way to add an attachment to a mail read from an stream using MimeKit?
I need something like this
var message = MimeMessage.Load(inputStream);
var newMessage = AddSomeInfoAttachment(message);
newMessage.WriteTo(outputStream)
The part in question is "AddSomeInfoAttachment(message)". The attachment (for now) is just a text file (a string in fact).
It appears to be easy if you create a new message (http://www.mimekit.net/docs/html/Creating-Messages.htm) but I suspect that it's way more complicated to start with an already created one (for instance: Where in the MIME tree is supposed to go the attachment? Do I have to copy all other parts to a newMessage or can I just modify the original message in place?)
So far the only "Attachments" collections (with an Add) I see is using a BodyBuilder and I suspect that is not that easy with an already loaded MimeMessage.
In the most common scenario, the following code snippet should do what you want/expect:
var message = MimeMessage.Load(fileName);
var attachment = new TextPart("plain") {
FileName = "attachment.txt",
ContentTransferEncoding = ContentEncoding.Base64,
Text = attachmentText
};
if (!(message.Body is Multipart multipart &&
multipart.ContentType.Matches("multipart", "mixed"))) {
// The top-level MIME part is not a multipart/mixed.
//
// Attachments are typically added to a multipart/mixed
// container which tends to be the top-level MIME part
// of the message (unless it is signed or encrypted).
//
// If the message is signed or encrypted, though, we do
// do not want to mess with the structure, so the correct
// thing to do there is to encapsulate the top-level part
// in a multipart/mixed just like we are going to do anyway.
multipart = new Multipart("mixed");
// Replace the message body with the multipart/mixed and
// add the old message body to it.
multipart.Add(message.Body);
message.Body = multipart;
}
// Add the attachment.
multipart.Add(attachment);
// Save the message back out to disk.
message.WriteTo(newFileName);

Unable to open the Excel file attached to work item in Azure Devops

I am creating a tool for attaching the excel files to work items using Azure Devops REST API.I am able to add the excel file to work item but when I was trying to open that it just says "file foramt or file extension not valid". I appreciate any suggestions or any inputs.
Edited:
As per the sugesstion of Lance-Li , i converted the excel file to bytes and send that in request body like below
byte[] filedata = File.ReadAllBytes(filepath);
dynamic WorkItem = new List<dynamic>() {
new
{
filedata,
}
};
var WorkItemValue = new StringContent(JsonConvert.SerializeObject(WorkItem),Encoding.UTF8, "application/json-patch+json");
now sending above workitem value to post method with content-type=application\octet-stream. but still i am facing format issue.did I make any mistake?
Normally we call Attachments-Create(Upload the attachment to the attachment store) and then Add an attachment(Add the attachment from attachment store to the work item) to add local attachment to workitem.
Cause of the issue:
We should be careful when we upload the attachment using first rest api(Attachments - Create). In the post request, the filename=xxx doesn't receive any path to the file. It won't fetch the file from desktop or other folders.
After several tests, I reproduced the same issue like yours. Also I find that if we run the post request, it actually just created one new file with same name instead of fetching local file. For example, if I have a local test.txt file with content just for test, in my request body I have "User text content to upload", the result is to get one attachment named test.txt with content "User text content to upload".
So I think you may upload a xx.xlsx file with text content. That's why we got file foramt not valid error.
Two workarounds:
1.Upload it as binary file, convert the excel file to binary file and paste the binary content to the request body. (About is it possible to convert excel and how to do that, that's another issue so I don't talk about it here)
2.Another workaround I finally found is using -Infile in Invoke-RestMethod command and it works well!
(If you're using something like postman to run the api, contenttype=>application/octet-stream, body=>binary)
My Powershell script about Attachments-Create:
$token = "YourPat"
$url="https://dev.azure.com/YourOrgName/_apis/wit/attachments?fileName=YourFileName.xlsx&api-version=5.1"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$filepath="YourFilePath\YourFileName.xlsx"
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -InFile $filepath -ContentType application/octet-stream
Write-Host $response
Hope all above helps :) And since the cause of the original issue is only about the usage of first api, so I won't talk about the second one here...
In addition: If someone is using C# client api to upload the binary file, try using contenttype application\json, info from dhulipala murali. And if someone is using PS/postman, application/octet-stream works well at my side.

Get the shortcut link from a .url shortcut file

I'm querying the graph api using this URL:
https://graph.microsoft.com/v1.0/sites/{siteID}/drives/{driveID}/root/children
which is giving me the webURL
"https://MY DOMAIN.sharepoint.com/sites/{SITE}/{FILENAME}.url
Is there any way to get the value that the shortcut item points to, as opposed to downloading a .url file?
I think Get url address from url file answers half of my question, however, I'm unable to get the contents of the url as a File type object to be able to read through it.
I'm getting each of the quicklinks and adding them to a list via ReadAsStringAsync
public static async Task<List<QuickLinkViewModel>> GetQuickLinksAsync (dynamic quicklinksJson)
{
List<QuickLinkViewModel> quickLinks = new List<QuickLinkViewModel>();
var quickLink = quicklinksJson.value;
string title;
HttpClient client = new HttpClient();
byte[] reply;
foreach (var q in quickLink)
{
reply = await client.GetByteArrayAsync(q.webUrl);
title = q.name;
title = System.IO.Path.GetFileNameWithoutExtension(title);
quickLinks.Add(new QuickLinkViewModel
{
Title = title,
webUrl = q.webUrl
});
}
return quickLinks;
}
When I run this I'm getting the error:
The best overloaded method match for
'System.Net.Http.HttpClient.GetByteArrayAsync(string)' has some
invalid arguments
.url file is not supported to be previewed in SharePoint. So the webUrl format in the query results of Microsoft Graph is different from other files. Other files can be previewed through this webUrl. The .url file will be downloaded directly through webUrl.
You can download it and open it with the edit tool to see the value that the shortcut item points to.
The content of .url file:
[InternetShortcut]
URL={the value that the shortcut item points to}
UPDATE:
If you want to get the content of the .url file in your code, you need to call another Graph endpoint: GET /drives/{drive-id}/items/{item-id}/content. See reference here. Use client.DownloadString to read the content in C#.
Here is a simple example (Please note that I didn't implement the authorization process here, just put the Authorization herder for convenience):

Attach PDF document to Email C# Windows Application - Email does not send out

I am trying to attach PDF document to MailMessage Send method in Windows Form Application. I am using below code to attach document to email.
mail.Attachments.Add(new Attachment(#"c:\Files\churchapplication.pdf"));
Email is not generated and no exception is raised either so i am unable to troubleshoot the problem. Same code works if I attach text file instead of pdf. So what could be the issue? Any ideas? PDF file size 291 KB. Is there some restrictions with attaching PDF documents in .NET?
Thanks.
You can try this multi-step approach.
//First create FileContent
FileContentResult fileContent = File(fileName, "application/pdf", "file.pdf");
MemoryStream ms = new MemoryStream(fileContent.FileContents);
// Create an in-memory System.IO.Stream
ContentType ct = new ContentType(fileContent.ContentType);
Attachment a = new Attachment(ms, ct);
sender.SendMail("email", "email", "subject", "Body", a);

How to download multiple attachments per message with MailKit?

I've looked at a lot of the other questions on stackoverflow about this, but I'm still confused.
I want to download the attachments of emails- I was successfully able to do this, but only if the email had ONE attachment; when an email has more than one attachment, it stops working.
How do I download multiple attachments per email?
Also, is there a way to determine the file extension when downloading? Currently, for example, if there is a pdf attachment, the file downloads, but with no .pdf, so windows doesn't know the file type.
The code below is from here: MailKit save Attachments. I've been basing my code off of that.
foreach (var attachment in message.Attachments)
{
using (var stream = File.Create ("fileName"))
{
if (attachment is MessagePart)
{
var part = (MessagePart) attachment;
part.Message.WriteTo (stream);
}
else
{
var part = (MimePart) attachment;
part.ContentObject.DecodeTo (stream);
}
}
}
Please help! Thanks!
The code you pasted will already save all attachments.
Look at the raw message source. Does each "attachment" that you consider to be an attachment have a header Content-Disposition: attachment? If not, that's the problem you are hitting.
You can instead use message.BodyParts and apply your own logic to determine if the part is what you would consider to be an "attachment".
Also, is there a way to determine the file extension when downloading? Currently, for example, if there is a pdf attachment, the file downloads, but with no .pdf, so windows doesn't know the file type.
Yes. You can check the file extension on the FileName property on MimePart objects.

Categories

Resources