jstedfast / MimeKit

A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
http://www.mimekit.net
MIT License
1.79k stars 360 forks source link

AttachmentCollection.Add() needs to handle message/rfc822 parsing exceptions #1001

Closed Sicos1977 closed 5 months ago

Sicos1977 commented 5 months ago

Using the latest MimeKit version,

When our system receives a e-mail it will try to process it. When this for whatever reason fails it forwards the message to another mailbox.

In this case I load the MimeMessage from Exchange Web Services and strip it apart in pieces... the body and attachments gets stored in a database. When I try to forward this message again I reassemble the message but this fails in the folowing case.

When the e-mail has another .EML file as an attachment and this attachment is corrupt (for whatever reason) then MimeKit throws the exception "Failed to parse message headers" ... this is correct because the file is corrupt. I can't prevent customers from sending corrupt attachments.

I debuged mimekit and tracked down the place where the exception is thrown.

at MimeKit.MimeParser.ParseMessage(Byte* inbuf, CancellationToken cancellationToken) at MimeKit.MimeParser.ParseMessage(CancellationToken cancellationToken) at MimeKit.MimeMessage.Load(ParserOptions options, Stream stream, Boolean persistent, CancellationToken cancellationToken) at MimeKit.AttachmentCollection.CreateAttachment(ContentType contentType, String path, Stream stream, Boolean copyStream, CancellationToken cancellationToken) at MimeKit.AttachmentCollection.Add(String fileName, Stream stream, CancellationToken cancellationToken) at Email2Storage.Server.BusinessLogic.Email.ToListOfMimeMessage(Boolean includeForwardReasons, Boolean includeForwardHeader, String forwardReasonsFileName, Int64 splitEmailMaxSize, Int32 splitEmailMaxMimeParts, String splitEmailSubjectPrefix, String splitEmailReason, String invalidEmailAddressReplacement, List1 headersToInclude, String referenceId) at Email2Storage.Services.Forwarding.ForwardingEmailWorker.d__31.MoveNext() | Failed to parse m `

The attachment is called Declaratie [24.01.0071] [DUDOK_23.0364.01] 20240109_105801.eml

bodyBuilder.Attachments.Add(attachment.FileName, attachment.FileData);

This goes to

        public MimeEntity Add (string fileName, Stream stream, CancellationToken cancellationToken = default)
        {
            if (fileName is null)
                throw new ArgumentNullException (nameof (fileName));

            if (fileName.Length == 0)
                throw new ArgumentException ("The specified file path is empty.", nameof (fileName));

            if (stream is null)
                throw new ArgumentNullException (nameof (stream));

            var attachment = CreateAttachment (GetMimeType (fileName), fileName, stream, true, cancellationToken);

            attachments.Add (attachment);

            return attachment;
        }

That calls CreateAttachment

That triggers this if statement

if (contentType.IsMimeType ("message", "rfc822"))

That calls this

        public static MimeMessage Load (Stream stream, CancellationToken cancellationToken = default)
        {
            return Load (ParserOptions.Default, stream, false, cancellationToken);
        }

And in the end throws the exception because the EML file is just giberisch because it is corrupt.

Sicos1977 commented 5 months ago

Nevermind... I fixed it like this

                try
                {
                    bodyBuilder.Attachments.Add(attachment.FileName, attachment.FileData);
                }
                catch (FormatException)
                {
                    bodyBuilder.Attachments.Add(attachment.FileName, attachment.FileData, new MimeKit.ContentType("application", "octet-stream"));
                }
jstedfast commented 5 months ago

Interesting...

Arguably, MimeKit's AttachmentCollection code should better handle this scenario.

I'm going to reopen.

jstedfast commented 5 months ago

I think that MimeKit should probably more-or-less handle this situation the way you've handled it.