Awesome
MimeParserBenchmark
This project benchmarks various .NET MIME parsers for comparison purposes.
Package Versions
Package | Version |
---|---|
<a href="https://github.com/jstedfast/MimeKit">MimeKit</a> | <a href="https://www.nuget.org/packages/MimeKit/3.0.0">3.0.0</a> |
<a href="https://www.limilabs.com/mail">LimiLabs' Mail.dll</a> | <a href="https://www.nuget.org/packages/Mail.dll/3.0.21294.1630">3.0.21294.1630</a> |
<a href="http://www.mime4.net/">Mime4Net</a> | <a href="https://www.nuget.org/packages/NI.Email.Mime/1.8.1">1.8.1</a> |
<a href="https://github.com/andyedinborough/aenetmail">AE.Net.Mail</a> | <a href="https://www.nuget.org/packages/AE.Net.Mail/1.7.10">1.7.10</a> |
<a href="https://github.com/pmengal/MailSystem.NET">MailSystem.NET</a> | <a href="https://www.nuget.org/packages/MailSystem.NET/2.0.1">2.0.1</a> |
<a href="https://github.com/foens/hpop">OpenPOP.NET</a> | <a href="https://www.nuget.org/packages/OpenPop.NET/2.0.6.1120">2.0.6.1120</a> |
Runtime
Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores
[Host] : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT
DefaultJob : .NET Framework 4.8 (4.8.4420.0), X64 RyuJIT
Results
HeavyHeaderEmailBenchmark
In this benchmark, each library is used to parse an in-memory email message that is almost all headers 1,000 times.
Method | Mean | Error | StdDev |
---|---|---|---|
MimeKit | 30.22 ms | 0.207 ms | 0.183 ms |
MimeKitPersistent | 30.08 ms | 0.311 ms | 0.276 ms |
LimiLabs | 629.92 ms | 3.252 ms | 2.883 ms |
Mime4Net | 517.56 ms | 3.442 ms | 3.051 ms |
OpenPOP | 353.23 ms | 4.355 ms | 4.074 ms |
AENetMail | 2,862.46 ms | 17.677 ms | 16.535 ms |
MailSystemNET | 1,911.98 ms | 11.197 ms | 10.474 ms |
JwzMboxBenchmark
In this benchmark, each library is used to parse the jwz.mbox
Unix mbox spool from disk 10 times.
Method | Mean | Error | StdDev |
---|---|---|---|
MimeKit | 171.3 ms | 0.87 ms | 0.77 ms |
MimeKitPersistent | 160.1 ms | 1.50 ms | 1.33 ms |
LimiLabs | 1,148.3 ms | 8.28 ms | 7.75 ms |
StarTrekEmailBenchmark
In this benchmark, each library is used to parse startrek.eml
from disk 1,000 times.
Method | Mean | Error | StdDev |
---|---|---|---|
MimeKit | 218.6 ms | 1.95 ms | 1.73 ms |
MimeKitPersistent | 205.5 ms | 1.72 ms | 1.61 ms |
LimiLabs | 2,318.0 ms | 12.37 ms | 10.96 ms |
Mime4Net | 10,726.6 ms | 38.19 ms | 35.73 ms |
OpenPOP | NA | NA | NA |
AENetMail | 3,897.4 ms | 74.18 ms | 69.39 ms |
MailSystemNET | 8,928.0 ms | 29.92 ms | 26.53 ms |
Notes:
- MailSystem.NET's parser only supports parsing from byte[] or MemoryStream, so in this test, MailSystem.NET is allowed to "cheat" by parsing an in-memory version of the message instead of being forced to parse from disk in each iteration.
- OpenPOP.NET fails to parse this message with the following exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Media Type must be in the format type "/" subtype
Parameter name: mediaType
at OpenPop.Mime.Header.HeaderFieldParser.cleanMediaType(String mediaType)
at OpenPop.Mime.Header.HeaderFieldParser.ParseContentType(String headerValue)
at OpenPop.Mime.Header.MessageHeader.ParseHeader(String headerName, String headerValue)
at OpenPop.Mime.Header.MessageHeader.ParseHeaders(NameValueCollection headers)
at OpenPop.Mime.Header.HeaderExtractor.ExtractHeadersAndBody(Byte[] fullRawMessage, MessageHeader& headers, Byte[]& body, IParsingErrorHandler parsingErrorHandler)
at OpenPop.Mime.MessagePart.ParseMultiPartBody(Byte[] rawBody)
at OpenPop.Mime.MessagePart.ParseMultiPartBody(Byte[] rawBody)
at OpenPop.Mime.Message.Load(Stream messageStream, IParsingErrorHandler parsingErrorHandler)
at Benchmarks.StarTrekEmailBenchmarks.OpenPOP()
at BenchmarkDotNet.Autogenerated.Runnable_14.WorkloadActionNoUnroll(Int64 invokeCount)
at BenchmarkDotNet.Engines.Engine.RunIteration(IterationData data)
at BenchmarkDotNet.Engines.EngineFactory.Jit(Engine engine, Int32 jitIndex, Int32 invokeCount, Int32 unrollFactor)
at BenchmarkDotNet.Engines.EngineFactory.CreateReadyToRun(EngineParameters engineParameters)
at BenchmarkDotNet.Autogenerated.Runnable_14.Run(IHost host, String benchmarkName)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at BenchmarkDotNet.Autogenerated.UniqueProgramName.AfterAssemblyLoadingAttached(String[] args)
Xamarin3EmailBenchmark
In this benchmark, each library is used to parse xamarin3.eml
from disk 1,000 times.
Method | Mean | Error | StdDev |
---|---|---|---|
MimeKit | 1.629 s | 0.0168 s | 0.0157 s |
MimeKitPersistent | 1.344 s | 0.0086 s | 0.0080 s |
LimiLabs | 12.503 s | 0.0421 s | 0.0394 s |
Mime4Net | 85.075 s | 0.4774 s | 0.3987 s |
OpenPOP | 80.162 s | 0.6835 s | 0.6059 s |
AENetMail | 30.925 s | 0.2161 s | 0.1915 s |
MailSystemNET | 48.179 s | 0.6107 s | 0.5713 s |
Notes:
- MailSystem.NET's parser only supports parsing from byte[] or MemoryStream, so in this test, MailSystem.NET is allowed to "cheat" by parsing an in-memory version of the message instead of being forced to parse from disk in each iteration.
Conclusions
Yea. No contest. MimeKit mops the floor with all of the other parsers out there.
How does your MIME parser compare?