Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read inline image in email body using Mailkit

Tags:

c#

mailkit

I have sent myself a test email which has an image in the body of the email. This image is not an attachment, just pasted into the body of the email.

I am using MailKit to read this incoming email, but cannot find how to access that image.

I'm using:

MimeMessage message = client.Inbox.GetMessage(uid);

If I use message.ToString(), I can see that it is there:

...
Content-Disposition: inline; filename="image001.png"; size=4570;
        creation-date="Mon, 16 Sep 2019 09:21:07 GMT";
        modification-date="Mon, 16 Sep 2019 09:21:07 GMT"
Content-ID: <[email protected]>
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAJUAAAAlCAY...

And I assume the base64 encoded lines are the actual image, but how do I get at it?

EDIT

Here is my test code:

    static void Main(string[] args)
    {
        ImapClient client = new ImapClient();
        client.Connect("...
        client.Authenticate("...
        client.Inbox.Open(FolderAccess.ReadWrite);
        IList<UniqueId> uids = client.Inbox.Search(SearchQuery.All);
        foreach (UniqueId uid in uids)
        {
            MimeMessage message = client.Inbox.GetMessage(uid);

            IList<IMessageSummary> info = client.Inbox.Fetch(new[] { uid }, MessageSummaryItems.All);

            foreach (MimeEntity me in message.Attachments)
                HandleMimeEntity(me, 1);
        }
        client.Disconnect(true);
    }

    static void HandleMimeEntity(MimeEntity entity)
    {
        int i, j;

        Multipart multipart = entity as Multipart;

        if (multipart != null)
        {
            Console.WriteLine("multipart");
            for (i = 0; i < multipart.Count; i++)
            {
                Console.WriteLine(i + " - " + multipart[i].ContentType.MimeType + " (" + multipart[i].IsAttachment + ")");
                HandleMimeEntity(multipart[i]);
            }
            return;
        }

        MessagePart rfc822 = entity as MessagePart;

        if (rfc822 != null)
        {
            MimeMessage message = rfc822.Message;
            Console.WriteLine("mimemessage - " + message.Subject);

            HandleMimeEntity(message.Body, lvl + 1);
            return;
        }

        MimePart part = (MimePart)entity;
        Console.WriteLine("mimepart - " + part.FileName);

        // do something with the MimePart, such as save content to disk
    }
like image 339
Graham Avatar asked Oct 17 '25 10:10

Graham


1 Answers

I would really, really, really recommend reading the FAQ and/or the README to understand how MIME is structured so that answers to questions like this become obvious, but in the meantime...

Let's start with the understanding that MIME is a tree structure, which means there's a root node (which may or may not be a leaf-node), there can be branch nodes (ex. multipart/mixed, multipart/alternative, multipart/related, etc.) and there are leaf-nodes (ex. text/plain, text/html, image/jpeg, application/octet-stream, etc.).

The root node of the MIME structure is the MimeMessage.Body property.

If the message contains only a text/plain MIME entity, then the MimeMessage.Body node will be that text/plain MIME entity.

In your case, it sounds like you have at least a text/html entity and an image/png entity.

Knowing nothing else about the structure of your message, we can conclude that MimeMessage.Body isn't the text/html entity nor the image/png entity because you can only have 1 root node and text/* and image/* parts are leaf-node entities, not branch node entities.

That means that MimeMessage.Body will be a multipart/* which will be represented by the Multipart (or a subclass thereof).

Since it's clear that the MimeMessage.Body in your case is a Multipart, we can cast it:

var multipart = (Multipart) message.Body;

Once we have the multipart, we can iterate over its children:

foreach (var child in multipart) {
    // ...
}

At this point we will need to figure out if the child is another Multipart, a MimePart (which will represent text or image data), or an embedded message (aka MessagePart).

You can use an as cast to quickly deduce what it is.

And then you just continue walking the tree of MIME entities until you find what you are looking for which will likely require some recursion using the above approach.

MimeKit has a few alternative ways to do this, however:

  1. MimeMessage.BodyParts
  2. MimeIterator
  3. and MimeVisitor

Here's a quick solution to your problem using the BodyParts property:

var myImage = message.BodyParts.OfType<MimePart> ().FirstOrDefault (x => x.IsMimeType ("image", "png"));
like image 65
jstedfast Avatar answered Oct 20 '25 00:10

jstedfast



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!