runtime: Reusing SmtpClient hangs in net50

Calling SendMailAsync multiple times on the same SmtpClient instance fails under some circumstances in net50.

Description

The following test succeeds when running under netcoreapp3.1, but fails by timing out in net50

[Fact(Timeout = 10000)]
public async Task Net50Repo()
{
    var config = Configuration.Configure();
    using var server = SimpleSmtpServer.Start(config.WithRandomPort().Port);
    var inst = new SmtpClient
    {
        Host = "localhost",
        Port = server.Configuration.Port,
        EnableSsl = false
    };

    for (int messageNo = 0; messageNo < 2; messageNo++)
    {
        var mailMessage = new MailMessage("one@example.com", "two@example.com");

        await inst.SendMailAsync(mailMessage);

        Assert.Equal(messageNo + 1, server.ReceivedEmailCount);
    }
}

The issue seems to be reusing the SmtpClient, the first SendMailAsync succeeds, but the second call always just hangs indefinitely.

Works in 3.1. Newing up a new client for each call also works. Testing against a different Smtp server (eg. Papercut) also works.

netDumpster just ends up waiting inside SmtpContext on this line:

count = this.socket.Receive(byteBuffer); It’s like if the socket remains open it cannot be reused anymore for some reason. Any idea what changed?

Configuration

We are able to reproduce with netdumpster in unit tests, production is not yet running in net50 for us (partly because of this), so I’m unsure if other smtp server are effected, we are nervous about this.

Regression?

Yes, regression from 3.1 to 5

Other information

I originally raised the issue on netdumpster, there is some more discussion there, although not much.

I am aware that other issues mention SmtpClient is not under active development, and it seems MS recommends migrating to MailKit, but it would still be nice if existing functionality would not break.

@cmendible @scalablecory

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 15 (14 by maintainers)

Most upvoted comments

FYI because possibly connected:

I’m reusing the same SmtpClient instance to send multiple e-mails via synchronous Send(MailMessage) method.

  • on .net Framework 4.7.2 and 4.8 this works without issue (Windows Server 2019)
  • on .net 6 same code results in the server closing the socket and reporting a timeout:

    SmtpException: Service not available, closing transmission channel. The server response was: Timeout. Try talking faster next time at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response) at System.Net.Mail.MailCommand.Send(SmtpConnection conn, Byte[] command, MailAddress from, Boolean allowUnicode) at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, Boolean allowUnicode, SmtpFailedRecipientException& exception) at System.Net.Mail.SmtpClient.Send(MailMessage message)

    • run on Windows Server 2019 as well as Linux, same timeouts happen on both

EDIT: Changing the implementation to use a new instance for every e-mail fixed the timeouts. See comment below.

I did quick check and I cannot reproduce it @chrisaut. Tested on Ubuntu18 agains Postfix.

I/we are on windows testing against netdumpster. Easiest to repro with this: https://github.com/cmendible/netDumbster/tree/dotnet5 The test called “Reusing_Smtp_Client_Should_Not_Fail” succeeds in 3.1 and fails in 5.0

What OS do you use? Can you do packet captures with Wireshark? Perhaps we can see more there.

Windows. I can probably get some captures if needed, but you should be able to repro with the branch above.

Just to be clear again, we originally thought this was a netdumpster (a fake smtp server for tests) issue, however it functions perfectly in older frameworks, and against other smtp clients. Upgrading to dotnet 50 breaks when using SmtpClient.

Like mentioned before, there was a bit of discussion earlier here