MimeParserBenchmark

May 10, 2025 ยท View on GitHub

This project benchmarks various .NET MIME parsers for comparison purposes.

Package Versions

PackageVersion
MimeKit4.12.0
LimiLabs' Mail.dll3.0.25121.1408
Mime4Net1.8.1
AE.Net.Mail1.7.10
MailSystem.NET2.0.1
OpenPOP.NET2.0.6.1120

Runtime

BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3775)
Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores
  [Host]     : .NET Framework 4.8.1 (4.8.9290.0), X64 RyuJIT VectorSize=256
  DefaultJob : .NET Framework 4.8.1 (4.8.9290.0), X64 RyuJIT VectorSize=256

Results

HeavyHeaderEmailBenchmark

In this benchmark, each library is used to parse an in-memory email message that is almost all headers 1,000 times.

MethodMeanErrorStdDev
MimeKit30.28 ms0.229 ms0.215 ms
MimeKitPersistent30.53 ms0.546 ms0.484 ms
LimiLabs729.34 ms7.569 ms6.321 ms
Mime4Net573.89 ms9.861 ms10.551 ms
OpenPOP399.10 ms7.696 ms8.554 ms
AENetMail2,912.24 ms57.274 ms70.338 ms
MailSystemNET1,954.23 ms25.525 ms22.627 ms

JwzMboxBenchmark

In this benchmark, each library is used to parse the jwz.mbox Unix mbox spool from disk 10 times.

MethodMeanErrorStdDev
MimeKit177.1 ms2.52 ms2.36 ms
MimeKitPersistent163.7 ms2.92 ms4.64 ms
LimiLabs1,166.2 ms23.01 ms21.52 ms

StarTrekEmailBenchmark

In this benchmark, each library is used to parse startrek.eml from disk 1,000 times.

MethodMeanErrorStdDev
MimeKit216.6 ms4.33 ms5.48 ms
MimeKitPersistent195.7 ms3.91 ms5.48 ms
LimiLabs5,776.4 ms110.47 ms118.20 ms
Mime4Net11,114.1 ms85.75 ms76.01 ms
OpenPOPNANANA
AENetMail4,018.5 ms26.65 ms20.80 ms
MailSystemNET9,528.9 ms127.01 ms99.16 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.

MethodMeanErrorStdDevMedian
MimeKit1.693 s0.0316 s0.0400 s1.679 s
MimeKitPersistent1.314 s0.0201 s0.0188 s1.312 s
LimiLabs14.392 s0.1196 s0.1060 s14.362 s
Mime4Net90.029 s1.0404 s0.9732 s90.027 s
OpenPOP78.548 s1.0670 s0.9981 s78.792 s
AENetMail31.338 s0.5670 s0.6529 s31.322 s
MailSystemNET54.039 s1.0752 s3.1363 s52.791 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?