cosullivan / SmtpServer

A SMTP Server component written in C#
MIT License
676 stars 160 forks source link

Session Faulted when having large recipient size on version 8 or 9 #163

Closed bogdanst24 closed 3 years ago

bogdanst24 commented 3 years ago

Bug: Session faulted on a large number of recipients Bug on versions: 8, 9

Starting with version 8 of the library, there is one critical issue that blocks us from updating. This, even though the performance improvements proved to be huge after performing a long load testing session (4-5 times faster in our case).

In our case, the SmtpServer is receiving emails from Exchange and the maximum number of recipients in one transaction is 500. Whenever a user sends an email to a DIstribution List with more than X members, the SmtpServer will immediately fail on Session Faulted throwing the following error. We have seen this happening with 200, 250, 300 recipients, and seeing the error it is clear that it would happen with anything more.

Specified argument was out of the range of valid values. (Parameter 'length')
at System.ThrowHelper.ThrowStartOrEndArgumentValidationException(Int64 start)\r\n   
at System.Buffers.ReadOnlySequence`1.Slice(Int64 start, Int64 length)\r\n  
at SmtpServer.Text.TokenReader.TryMake(TryMakeDelegate delegate, ReadOnlySequence`1& buffer)\r\n  
at SmtpServer.Protocol.SmtpParser.TryMakeMailbox(TokenReader& reader, IMailbox& mailbox)\r\n   
at SmtpServer.Protocol.SmtpParser.TryMakePath(TokenReader& reader, IMailbox& mailbox)\r\n   
at SmtpServer.Protocol.SmtpParser.TryMakeRcpt(TokenReader& reader, SmtpCommand& command, SmtpResponse& errorResponse)\r\n  
at SmtpServer.Protocol.SmtpParser.<TryMake>g__Make|4_0(ReadOnlySequence`1 buffer, TryMakeDelegate tryMakeDelegate, SmtpCommand& command, SmtpResponse& errorResponse)\r\n   
at SmtpServer.Protocol.SmtpParser.TryMake(ReadOnlySequence`1& buffer, SmtpCommand& command, SmtpResponse& errorResponse)\r\n   
at SmtpServer.SmtpSession.<>c__DisplayClass6_0.<ReadCommandAsync>b__0(ReadOnlySequence`1  buffer)\r\n   
at SmtpServer.IO.PipeReaderExtensions.ReadUntilAsync(PipeReader reader, Byte[] sequence, Func`2 func, CancellationToken cancellationToken)\r\n   
at SmtpServer.SmtpSession.ReadCommandAsync(ISessionContext context, CancellationToken cancellationToken)\r\n   
at SmtpServer.SmtpSession.ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)\r\n   
at SmtpServer.SmtpSession.RunAsync(CancellationToken cancellationToken)\r\n   
at SmtpServer.SmtpSessionManager.RunAsync(SmtpSessionHandle handle, CancellationToken cancellationToken)

Unfortunately, this is how Exchange Online deals with distribution lists, expanding them before sending the mail out, so all recipients are listed instead of the distribution list address. The impact of this issue is that emails being sent to distribution lists or lots of recipients are not going through.

Please help and thank you for your work. Let me know if any more logs are needed

cosullivan commented 3 years ago

Ok, I have never tested it with such a large number of recipients before, but I will look into it over the next few days.

Thanks, Cain.

cosullivan commented 3 years ago

@bogdanst24 I'm not sure how sensitive the email addresses are that you are using but if you are able to send them to me (on email) then that would help, but I understand if you don't want to.

I don't think it is an issue with a large number of recipients, but rather one or more of the recipients themselves. Based on that exception, the error is occurring whilst trying to make/parse the mailbox. With the SMTP protocol, even if the mail client is trying to send 500 different recipients they should all be issued as their own RCPT TO command and therefore each is processed separately.

I will have a look through the code anyway and see if there is something that could be causing it.

bogdanst24 commented 3 years ago

Yes, you are right with the RCPT To being issues as individual recipients. From a total of 250, the error is thrown after the 100th or something similar. I'm sure it is not related to mailbox/address parsing, as it was reproduced on multiple different domains. It is an issue that was reported as critical by many customers (of our product using the library) and we are now also able to reproduce it locally.

I can give you any useful information, just that in this specific case I'm not sure how to provide something useful. In the sender side, it is a distribution list (so one recipient). At the same time, the SMTP Server crashes before making the mime message available. I have forwarded you one message on email.

cosullivan commented 3 years ago

Thanks, I have seen your email now and I can reproduce it. As you have said its related somehow to the number of emails being sent so I should be able to figure it out now.

Thanks for your input, I will have a look in the next day or two.

cosullivan commented 3 years ago

Ok, I think this issue is now resolved in v9.0.1 which I have just published.

There was an issue when it was reading tokens from multiple buffers which would likely only happen on large amounts of data being read from the client.

bogdanst24 commented 3 years ago

Awesome! I'll test it as soon as possible and come back with results

bogdanst24 commented 3 years ago

I can confirm that the issue is fixed now. Thank you!