How to download multiple attachments per message with MailKit? - c#

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.

Related

Download .eml file with Microsoft Graph 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);

Select attachments using Exchange Web Services

Sorry if my post is a duplicate one, I tried to find a solution without success.
I need to read an Office365 email folder and get the attachments contained in each mail.
I use this code
foreach (Attachment attachment in message.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
// Load the attachment into a file.
// This call results in a GetAttachment call to EWS.
fileAttachment.Load("C:\\temp\\" + fileAttachment.Name);
Console.WriteLine("File attachment name: " + fileAttachment.Name);
}
else // Attachment is an item attachment.
{
ItemAttachment itemAttachment = attachment as ItemAttachment;
// Load attachment into memory and write out the subject.
// This does not save the file like it does with a file attachment.
// This call results in a GetAttachment call to EWS.
itemAttachment.Load();
Console.WriteLine("Item attachment name: " + itemAttachment.Name);
}
}
taken from here link to do this.
But together the "real" attachments sent by the sender (pdf files, xls, or images too) the code downloads all the elements contained in each mail, i.e. logos, images inside the html body, etc.
There is a way to select only the "real" attachments and to avoid downloading logos, and other html elements contained inside the body?
Thanks for your help.
Lucius
You should be able to filter based on the other property on the Fileattachment class https://learn.microsoft.com/en-us/dotnet/api/microsoft.exchange.webservices.data.fileattachment?view=exchange-ews-api
eg
if(!Attachment.IsInline)
or check the if the ContentId is null etc

How to attach .docx and .doc files to the email from memory stream?

I'm doing the file attachment through memory stream because temporary storage is not an option.
Here I did a Jpeg image attachment. I looked at other file types with which you could do the same by switching the MediaTypeNames, and unfortunately .doc and .docx is not among them.
I was wondering whether any of you know of any package and how to use it for this particular occasion?
//...set up MailMessage, add a bunch of non-file content to it
MemoryStream jpgStream = new MemoryStream();
string filename = uploadedFile.FileName;
System.Drawing.Image theImage = System.Drawing.Image.FromStream(uploadedFile.InputStream);
theImage.Save(jpgStream, System.Drawing.Imaging.ImageFormat.Jpeg);
jpgStream.Seek(0L, SeekOrigin.Begin);
emailMessage.Attachments.Add(new Attachment(jpgStream, filename, System.Net.Mime.MediaTypeNames.Image.Jpeg));
//something extra and send email...
You should use MediaTypeNames.Application.Octet as mime type.
From : https://learn.microsoft.com/fr-fr/dotnet/api/system.net.mime.mediatypenames.application.octet?view=netframework-4.7.2
Thanks Benoit Gidon for his answer. I was proved once again that your assumptions are your worst enemy.
Apparently it's as simple as that and you don't need any other special methods as long as you put the file.InputStream in directly into attachment, unlike other S.O. posts make you believe:
https://stackoverflow.com/questions/9095880/attach-multiple-image-formats-not-just-jpg-to-email
https://stackoverflow.com/questions/5336239/attach-a-file-from-memorystream-to-a-mailmessage-in-c-sharp
In case anyone is actually struggling with it, here is the code:
foreach (HttpPostedFileBase file in fullViewModel.filesCollection)
{
string filename = file.FileName;
msg.Attachments.Add(new Attachment(file.InputStream, filename, MediaTypeNames.Application.Octet));
}
I tested this with a .docx document that had 5000 words of content in it, as well as tables and pictures, and it gets reconstructed the way it was in my gmail client.
Just tested that, it also works the same way with .png, so no need for PngBitmapDecoder.

C# Pdf Attachment damaged when sent to yahoo mail addresses

I'm trying to send an Email with an attached PDF file. When I send it to any other mail provider it works just fine, but when I send it to a yahoo email address, the receiver gets a damaged pdf file. The exact message it gives is:
Adobe Reader could not open 'Filename.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
Because the other email providers were working, I used the following code specifically for yahoo addresses.
if (thisItem.EmailAddress.ToUpper().Contains("YAHOO")){
ContentType contentType = new ContentType();
contentType.CharSet = Encoding.UTF8.WebName;
Attachment theFile = new Attachment(attachmentPath, contentType);
theFile.Name = theFile.Name.Replace("_","");
mm.Attachments.Add(theFile);
}
I've tried a variety of CharSets on the ContentType, hoping that would fix something, no change. I also tried different TransferEncodings on theFile, also no fix. I read somewhere that the file name could cause problems if it had special characters so I removed all the underscores in the name, all that's left is some letters and numbers. I'm not sure what else to try at this point. Any suggestions?

Lotus Notes - Saving Corrupt Attachment Programmatically - NotesEmbeddedObject

I have an NSF that contains an email message with two attachments. One of the attachments is corrupt, and if I attempt to save it, Notes displays this message The attachment may be corrupted. Would you like to continue with the available data?
If I click Yes, Notes saves the corrupt attachment to the directory I specify. This is good.
I would like to do the same thing using the object model in C#. If I run NotesEmbeddedObject.ExtractFile(), I receive this exception message: Notes error: Encoded Data Checksum Mismatch - Attachment may be corrupted. No version of the file is written to the directory I specify.
I would like for the code to write the corrupted version to a directory. How can I do this?
Existing Code:
//BEGIN Extract Attachment
//nItem is a NotesItem
if (nItem.type == IT_TYPE.ATTACHMENT)
{
try
{
string pAttachment = ((object[])nItem.Values)[0].ToString();
NotesDocument NDoc = NotesConnectionDatabase.AllDocuments.GetNthDocument(i);
NotesEmbeddedObject Neo = NDoc.GetAttachment(pAttachment);
NDoc.GetAttachment(pAttachment).ExtractFile(#"D:\projects\xxx\Attach\" + pAttachment);
}
catch (Exception e)
{
string eMessage = e.Message;
Console.WriteLine(eMessage);
}
}
//END Extract Attachment
I'm afraid not.
The NotesEmbeddedObject.ExtractFile method attempts to extract the attachment, but there's a checksum mismatch, and as soon as it gets that error, it throws an exception.
I don't know of any other Notes back-end classes that deal with attachments (maybe someone else does...)

Categories

Resources