0

I have a .Net5 application and I am trying to send emails using SmtpClient. As I understand it, I should wrap it in a Using statement

So I have the following

using(SmtpClient client = new SmtpClient(host, port))
{
   ....my code.....
   client.SendAsync(message, userState);
}

However this succeeds but I never receive the email.

If I change the code to

SmtpClient client = new SmtpClient(host, port);
....my code.....
client.SendAsync(message, userState);

Then I do receive the email.

I take it that client is being disposed before the email has been sent correctly but then I thought "using" was supposed to handle that properly?

What is the best practice to dispose of client? Also I may need to send multiple emails in using the same code so I need to make sure the client new gets created each time so that I do not dispose of it while it is sending another email.

coolblue2000
  • 3,796
  • 10
  • 41
  • 62

1 Answers1

2

You need to use a callback to get the result of the SendAsync call.

Also because you are inside a "using" statement the SmtpClient instance gets disposed before it gets a chance to finish the request.

You get the result of your call like this:

    static bool mailSent = false;
    private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // Get the unique identifier for this asynchronous operation.
         String token = (string) e.UserState;

        if (e.Cancelled)
        {
             Console.WriteLine("[{0}] Send canceled.", token);
        }
        if (e.Error != null)
        {
             Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
        } else
        {
            Console.WriteLine("Message sent.");
        }
        mailSent = true;
    }

        //.... in some other place in the code where your SmptClient lives
        client.SendCompleted += new
        SendCompletedEventHandler(SendCompletedCallback);
        // The userState can be any object that allows your callback
        // method to identify this send operation.
        // For this example, the userToken is a string constant.
    
        client.SendAsync(message, userState);
        //wait for the mail to be sent
        while(!mailSent)
        {
        }

And basically with SmtpClient the SendAsync works if you do not dispose the instance until after the request is over.

Basically you could potentially dispose of the instance in the completed event or by waiting on a boolean for example.

It is not ideal but then again the SmtpClient class is obsolete.

The example was taken directly from Microsoft's documentation SmtpClient

Jonathan Alfaro
  • 4,013
  • 3
  • 29
  • 32
  • 1
    So is there a new method of sending an email? The article seems to suggest using a third party library... Surely .net5 has its own smtp mail sending libraries? – coolblue2000 May 09 '21 at 17:35
  • 2
    @coolblue2000 nope. Microsoft has basically deprecated SmtpClient and they will not be implementing a new one. They suggest to use MailKit (and so do I) which is a modern mail client with more bells and whistles than the built in ever had. But you can switch to SendMailAsync which is a Task-returning method that you can await which would solve some of your problems – pinkfloydx33 May 09 '21 at 19:42
  • 1
    Microsoft has basically said thet SmtpClient is obsolete.. I have sience moved to MailKit my self. – Jonathan Alfaro May 09 '21 at 23:01