Handling Emails with Unusual or Unconventional MIME Structure

In rare cases, an email’s MIME might be structured in a way that is highly unusual and doesn’t follow conventions. In other words, the nested MIME structure of an email should follow conventions that make it possible to semantically understand the purpose of each MIME part — such as an attachment, or an image to be included in the HTML body, or a signature, etc.

For example, the defacto standard MIME structure for an email containing one attachment (which happens to be a .zip archive), and both plain-text and HTML alternative bodies, and a single JPG image reference from the HTML, is this:

multipart/mixed
    multipart/alternative
        text/plain
        multipart/related
            text/html
            image/jpeg
    application/zip
You can examine the MIME structure of any email less than 5MB in size by using Chilkat’s online tool at Examine MIME Structure.

If an email’s MIME structure is highly unusual, then it’s likely necessary to use the Chilkat.Mime class for processing. Chilkat MIME provides a lower-level API for MIME. For example, Chilkat recently encountered some emails with the following MIME structures:

multipart/mixed
    multipart/signed
        multipart/mixed
            multipart/alternative
                text/plain
                text/html
            message/rfc822
        application/pkcs7-signature
    multipart/alternative
        text/plain
        text/html

and

multipart/mixed
    multipart/signed
        multipart/mixed
            multipart/alternative
                text/plain
                text/html
            application/pdf
            application/pdf
        application/pkcs7-signature
    multipart/alternative
        text/plain
        text/html

To process more arbitrary MIME such as the above, one could write a recursive function such as this one in C#:


        private void recursivelyTraverseMime(Chilkat.Mime mime)
            {
            // If this MIME part is multipart, then recursively process the sub-parts.
            if (mime.NumParts > 0)
                {
                for (int i = 0; i < mime.NumParts; i++)
                    {
                    recursivelyTraverseMime(mime.GetPart(i));
                    }

                return;
                }

            // If we get here, then this part is not multipart..
            // Process according to the Content-Type and/or Disposition 
            textBox1.AppendText(mime.ContentType + ", Disposition = " + mime.Disposition + "\r\n");

            if (mime.ContentType.Equals("message/rfc822"))
                {
                // This MIME sub-part's body contains another MIME message..
                Chilkat.Mime mime2 = new Chilkat.Mime();
                Chilkat.BinData bd = new Chilkat.BinData();
                // Get the body of this sub-part and load it into mime2.
                mime.GetBodyBd(bd);
                if (mime2.LoadMimeBd(bd))
                    {
                    recursivelyTraverseMime(mime2);
                    }
                }
            else if (mime.Disposition.Equals("attachment"))
                {
                // Semantically, this is intended to be an attachment...
                // Perhaps you wish to get the content of the attachment..
                if (mime.ContentType.StartsWith("text/"))
                    {
                    string text = mime.GetBodyDecoded();
                    }
                else
                    {
                    byte[] data = mime.GetBodyBinary();
                    }
                }
            else if (mime.ContentType.Equals("text/plain"))
                {
                // This is a plain-text email body.
                string plainTextBody = mime.GetBodyDecoded();
                }
            else if (mime.ContentType.Equals("text/html"))
                {
                // This is an HTML email body.
                string htmlBody = mime.GetBodyDecoded();
                }
            // Continue with other ContentType's you wish to handle...
          
            }

        private void recursiveTraverseToolStripMenuItem_Click(object sender, EventArgs e)
            {
            Chilkat.Mime mime = new Chilkat.Mime();

            if (!mime.LoadMimeFile("c:/aaworkarea/samples/testV0.eml"))
                {
                MessageBox.Show("Failed to load MIME file.");
                return;
                }

            recursivelyTraverseMime(mime);
            }

Tags :