A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
| Package | Latest Release | Latest Build |
|---|---|---|
| MimeKit | ||
| MimeKitLite | ||
| MailKit | ||
| MailKitLite |
| Platform | Build Status | Code Coverage | Static Analysis |
|---|---|---|---|
| Linux/Mac | |||
| Windows |
MimeKit is a C# library which may be used for the creation and parsing of messages using the Multipurpose Internet Mail Extension (MIME), as defined by numerous IETF specifications.
MimeKit is a personal open source project that I have put thousands of hours into perfecting with the goal of making it the very best MIME parser framework for .NET. I need your help to achieve this.
Donating helps pay for things such as web hosting, domain registration and licenses for developer tools such as a performance profiler, memory profiler, a static code analysis tool, and more. It also helps motivate me to continue working on the project.
As a developer and user of email clients, I had come to realize that the vast majority of email client (and server) software had less-than-satisfactory MIME implementations. More often than not these email clients created broken MIME messages and/or would incorrectly try to parse a MIME message thus subtracting from the full benefits that MIME was meant to provide. MimeKit is meant to address this issue by following the MIME specification as closely as possible while also providing programmers with an extremely easy to use high-level API.
This led me, at first, to implement another MIME parser library called GMime which is implemented in C and later added a C# binding called GMime-Sharp.
Now that I typically find myself working in C# rather than lower level languages like C, I decided to begin writing a new parser in C# which would not depend on GMime. This would also allow me to have more flexibility in that I'd be able to use Generics and create a more .NET-compliant API.
While mainstream beliefs may suggest that C# can never be as fast as C, it turns out that with a bit of creative parser design and a few clever optimizations [1] [2], MimeKit's performance is actually on par with GMime.
Since GMime is pretty well-known as a high-performance native MIME parser and MimeKit more-or-less matches GMime's performance, it stands to reason that MimeKit is likely unsurpassed in performance in the .NET MIME parser space.
For a comparison, as I blogged here (I have since optimized MimeKit by at least another 30%), MimeKit is more than 25x faster than OpenPOP.NET, 75x faster than SharpMimeTools, and 65x faster than regex-based parsers. Even the commercial MIME parser offerings such as LimiLabs' Mail.dll and NewtonIdeas' Mime4Net cannot even come close to matching MimeKit's performance (they are both orders of magnitude slower than MimeKit).
For comparison purposes, I've published a MIME parser benchmark to make it easier for anyone else to compare the performance of MimeKit to their favourite MIME parser.
Here are the results:
Parsing startrek.msg (1000 iterations):
MimeKit: 0.6989221 seconds
OpenPop: 25.3056064 seconds
AE.Net.Mail: 17.5971438 seconds
MailSystem.NET: 26.3891218 seconds
MIMER: 76.4538978 seconds
Parsing xamarin3.msg (1000 iterations):
MimeKit: 3.4215505 seconds
OpenPop: 159.3308053 seconds
AE.Net.Mail: 132.3044291 seconds
MailSystem.NET: 133.5832078 seconds
MIMER: 784.433441 secondsHow does your MIME parser compare?
…The easiest way to install MimeKit is via NuGet.
In Visual Studio's Package Manager Console, enter the following command:
Install-Package MimeKitFirst, you'll need to clone MimeKit from my GitHub repository. To do this using the command-line version of Git, you'll need to issue the following command in your terminal:
git clone --recursive https://github.com/jstedfast/MimeKit.gitIf you are using TortoiseGit on Windows, you'll need to right-click in the directory where you'd like to clone MimeKit and select Git Clone... in the menu. Once you do that, you'll get the following dialog:
Fill in the areas outlined in red and then click OK. This will recursively clone MimeKit onto your local machine.
Occasionally you might want to update your local copy of the source code if I have made changes to MimeKit since you downloaded the source code in the step above. To do this using the command-line version fo Git, you'll need to issue the following commands in your terminal within the MimeKit directory:
git pull
git submodule updateIf you are using TortoiseGit on Windows, you'll need to right-click on the MimeKit directory and select Git Sync... in the menu. Once you do that, you'll need to click the Pull and Submodule Update buttons in the following dialog:
In the top-level MimeKit directory, there are a number of solution files; they are:
Once you've opened the appropriate MimeKit solution file in Visual Studio, you can choose the Debug or Release build configuration and then build.
Both Visual Studio 2022 and Visual Studio 2019 should be able to build MimeKit without any issues, but older versions such as Visual Studio 2015 and 2017 will require modifications to the projects in order to build correctly. It has been reported that adding NuGet package references to Microsoft.Net.Compilers >= 3.6.0 and System.ValueTuple >= 4.5.0 will allow MimeKit to build successfully.
Note: The Release build will generate the xml API documentation, but the Debug build will not.
One of the more common operations that MimeKit is meant for is parsing email messages from arbitrary streams. There are two ways of accomplishing this task.
The first way is to use one of the Load methods
on MimeMessage:
// Load a MimeMessage from a stream
var message = MimeMessage.Load (stream);Or you can load a message from a file path:
// Load a MimeMessage from a file path
var message = MimeMessage.Load ("message.eml");The second way is to use the MimeParser class. For the most
part, using the MimeParser directly is not necessary unless you wish to parse a Unix mbox file stream. However, this is
how you would do it:
// Load a MimeMessage from a stream
var parser = new MimeParser (stream, MimeFormat.Entity);
var message = parser.ParseMessage ();For Unix mbox file streams, you would use the parser like this:
// Load every message from a Unix mbox
var parser = new MimeParser (stream, MimeFormat.Mbox);
while (!parser.IsEndOfStream) {
var message = parser.ParseMessage ();
// do something with the message
}A common misunderstanding about email is that there is a well-defined message body and then a list of attachments. This is not really the case. The reality is that MIME is a tree structure of content, much like a file system.
Luckily, MIME does define a set of general rules for how mail clients should interpret this tree
structure of MIME parts. The Content-Disposition header is meant to provide hints to the receiving
client as to which parts are meant to be displayed as part of the message body and which are meant
to be interpreted as attachments.
The Content-Disposition header will generally have one of two values: inline or attachment.
The meaning of these values should be fairly obvious. If the value is attachment, then the content
of said MIME part is meant to be presented as a file attachment separate from the core message.
However, if the value is inline, then the content of that MIME part is meant to be displayed inline
within the mail client's rendering of the core message body. If the Content-Disposition header does
not exist, then it should be treated as if the value were inline.
Technically, every part that lacks a Content-Disposition header or that is marked as inline, then,
is part of the core message body.
There's a bit more to it than that, though.
Modern MIME messages will often contain a multipart/alternative MIME container which will generally contain
a text/plain and text/html version of the text that the sender wrote. The text/html version is typically
formatted much closer to what the sender saw in his or her WYSIWYG editor than the text/plain version.
The reason for sending the message text in both formats is that not all mail clients are capable of displaying HTML.
The receiving client should only display one of the alternative views contained within the multipart/alternative
container. Since alternative views are listed in order of least faithful to most faithful with what the sender
saw in his or her WYSIWYG editor, the receiving client should walk over the list of alternative views starting
at the end and working backwards until it finds a part that it is capable of displaying.
Example:
multipart/alternative
text/plain
text/htmlAs seen in the example above, the text/html part is listed last because it is the most faithful to
what the sender saw in his or her WYSIWYG editor when writing the message.
To make matters even more complicated, sometimes modern mail clients will use a multipart/related
MIME container instead of a simple text/html part in order to embed images and other content
within the HTML.
Example:
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
video/mp4
image/pngIn the example above, one of the alternative views is a multipart/related container which contains
an HTML version of the message body that references the sibling video and images.
Now that you have a rough idea of how a message is structured and how to interpret various MIME entities, the next step is learning how to traverse the MIME tree using MimeKit.
No
No open issues yet, or sync has not completed.