Saving attachments using MailKit library ?
Asked Answered
A

2

10

I'm trying to learn how to use the MailKit library but I am struggling to retrieve attachments. So far my code will open a mailbox, go through each message and store data such as sender, subject, body, date etc. but I can't deal with attachments.

I have tried to use other peoples solutions found on here, on github and other sites but I still don't understand exactly what they are doing in their code and when I come close to getting a solution working it causes more bugs so I get stressed and delete all the code. I don't mean to seem lazy but I would love if somebody could explain how I can achieve this. I'm basically trying to build a mail client for a web forms app.

Below is my code, so as you can see I'm fairly clueless :)

        // Open the Inbox folder
        client.Inbox.Open(FolderAccess.ReadOnly, cancel.Token);

        //get the full summary information to retrieve all details
        var summary = client.Inbox.Fetch(0, -1, MessageSummaryItems.Full, cancel.Token);
        foreach (var msg in summary)
        {
            //this code originally downloaded just the text from the body
            var text = msg.Body as BodyPartText;
            //but I tried altering it so that it will get attachments here also
            var attachments = msg.Body as BodyPartBasic;

            if (text == null)
            {
                var multipart = msg.Body as BodyPartMultipart;

                if (multipart != null)
                {
                    text = multipart.BodyParts.OfType<BodyPartText>().FirstOrDefault();
                }
            }

            if (text == null)
                continue;

            //I hoped this would get the messages where the content dispositon was not null
            //and let me do something like save the attachments somewhere but instead it throws exceptions
            //about the object reference not set to an instance of the object so it's very wrong
            if (attachments.ContentDisposition != null && attachments.ContentDisposition.IsAttachment)
            {
                //I tried to do the same as I did with the text here and grab the body part....... but no 
                var attachedpart = client.Inbox.GetBodyPart(msg.Index, attachments, cancel.Token);
            }

            else 
            {
                //there is no plan b :(
            }

            // this will download *just* the text 
            var part = client.Inbox.GetBodyPart(msg.Index, text, cancel.Token);
            //cast main body text to Text Part
            TextPart _body = (TextPart)part;
Alger answered 27/6, 2014 at 15:28 Comment(1)
What, exactly, do you want to do? Do you just want to download the attachments and save them off to disk (or some place)? What about the main body text?Urrutia
U
17

I'm not entirely clear on what you want to accomplish, but if you just want to download the message attachments (without downloading the entire message) and save those attachments to the file system, here's how you can accomplish that:

var messages = client.Inbox.Fetch (0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId);
int unnamed = 0;

foreach (var message in messages) {
    var multipart = message.Body as BodyPartMultipart;
    var basic = message.Body as BodyPartBasic;

    if (multipart != null) {
        foreach (var attachment in multipart.BodyParts.OfType<BodyPartBasic> ().Where (x => x.IsAttachment)) {
            var mime = (MimePart) client.Inbox.GetBodyPart (message.UniqueId.Value, attachment);
            var fileName = mime.FileName;

            if (string.IsNullOrEmpty (fileName))
                fileName = string.Format ("unnamed-{0}", ++unnamed);

            using (var stream = File.Create (fileName))
                mime.ContentObject.DecodeTo (stream);
        }
    } else if (basic != null && basic.IsAttachment) {
        var mime = (MimePart) client.Inbox.GetBodyPart (message.UniqueId.Value, basic);
        var fileName = mime.FileName;

        if (string.IsNullOrEmpty (fileName))
            fileName = string.Format ("unnamed-{0}", ++unnamed);

        using (var stream = File.Create (fileName))
            mime.ContentObject.DecodeTo (stream);
    }
}
Urrutia answered 28/6, 2014 at 1:13 Comment(3)
Hi, sorry for the delayed reply ,I was away all weekend. The answer you gave is a huge help and I have it working as I want now :) I needed to figure out how to check messages for attachments and then do something with them for example write to disk. I am currently trying to build a simple mail client like Gmail, Outlook etc. that you can configure to any mail server any it will retrieve all your mail and store it locally in a database, then display it to the user along with control over attached files. Sorry for all the questions but your library is by far the best :) Thanks again!Alger
@Urrutia i tried your code above, im unable to get inline messages, as they have isattachment property falseAlverson
You don't need to check IsAttachment if you don't want toUrrutia
S
5

Another alternative that works for me, but appears to be a little simpler:

var messages = client.Inbox.Fetch (0, -1, MessageSummaryItems.Full | MessageSummaryItems.BodyStructure | MessageSummaryItems.UniqueId);
int unnamed = 0;

foreach (var message in messages) {
    foreach (var attachment in message.Attachments) {
        var mime = (MimePart) client.Inbox.GetBodyPart (message.UniqueId.Value, attachment);
        var fileName = mime.FileName;

        if (string.IsNullOrEmpty (fileName))
            fileName = string.Format ("unnamed-{0}", ++unnamed);

        using (var stream = File.Create (fileName))
            mime.ContentObject.DecodeTo (stream);
    }
}

Note that this is asking for the BODYSTRUCTURE instead of the BODY in the Fetch statement, which seems to fix the issue of attachments not being flagged as such.

Scyros answered 27/10, 2016 at 10:28 Comment(1)
Ha cheers for this, I haven't looked at the library in a while but was thinking of trying it out again on a new project. Learned a bit since the last time I asked for help here but thanks for adding to it :)Alger

© 2022 - 2024 — McMap. All rights reserved.