My musings about .NET and what not

New in .NET 4: Don’t Forget to Dispose() your SmtpClient Instances

It seems the System.Net.Mail.SmptClient class has gotten a bit of a facelift in .NET 4.


Wow, it seems like forever since I’ve written a blog post. That’s because I’ve been heads-down on my new book, part of which involves getting up to speed on all of the newest features in ASP.NET 4.0.

I gotta admit that this one caught me by surprise though.

For the record, I will admit that I'm a little fanatical about disposing objects. As you (I hope) already know, that means remembering to call the Dispose() method on objects whose classes implement the IDisposable interface. It’s often tricky to remember which objects you need to dispose, since in many cases it’s not immediately obvious.

I thought I had this disposing stuff pretty much in my back pocket. That’s why I was so surprised when running some static code analysis on my Cyclemania project and seeing the following warning:

Warning    20    CA2000 : Microsoft.Reliability : In method 'TestEmail.btnSendTest_Click(object, EventArgs)', call System.IDisposable.Dispose on object 'new SmtpClient()' before all references to it are out of scope.

Whaaa??? What’s this? This can’t be right…

image

Well, as it turns out, the SmtpClient class does implement IDisposable, starting in .NET 4.

image

This is actually a good thing. The .NET 4 implementation of the SmtpClient class pools SMTP connections, which avoids the overhead of re-establishing a connection for every message when sending multiple messages to the same server. Since the same connection can be reused over and over in an application, there’s no way to determine when an application is finished using the client object. Calling Dispose() on it iterates through all established connections and sends a QUIT message, which allows the server to free up its own connection resources and begin processing. The TCP connection is then terminated, and any resources used by the underlying socket are released.

This means that, when you’re using SmtpClient to send mail in your .NET 4 application, you should adhere to the following:

// correct
try
{
   using (MailMessage message = new MailMessage())
   {
      message.Subject = "Test Email";
      message.Body = "This is a test email from .NET 4!";
      message.To.Add("[email protected]");

      using (SmtpClient client = new SmtpClient())
      {
         client.Send(message);
      }
   }
}         
catch (SmtpException)
{
   // handle exception here
}


// wrong
try
{
  using (MailMessage message = new MailMessage())
  {               
     message.Subject = "Test Email";
     message.Body = "This is a test email from .NET 3.5!";                  
     message.To.Add("[email protected]");

     new SmtpClient().Send(message);            
  }            
}         
catch (SmtpException)
{
  // handle exception here
}

Just one more .NET 4 “gotcha” to keep in mind.

UPDATE: Jeff Tucker (the guy who implemented this new feature) also points out in the comments below that SmtpClient will also close existing connections if you switch the host or port. Nice!

Subscribe to this blog for more cool content like this!

kick it on DotNetKicks.com

shout it on DotNetShoutOut.com

vote it on WebDevVote.com

Bookmark / Share

    » Similar Posts

    1. If At First You Don’t Succeed - Retrying Mail Operations in .NET
    2. Integrating Exception Handling Into the Development Cycle
    3. Singletons vs. Static Classes

    » Trackbacks & Pingbacks

    1. Pingback from Dew Drop – February 24, 2010 | Alvin Ashcraft's Morning Dew

      Dew Drop – February 24, 2010 | Alvin Ashcraft's Morning Dew — February 24, 2010 6:45 AM
    2. Pingback from Dew Drop – February 24, 2010 | Alvin Ashcraft's Morning Dew

      Dew Drop – February 24, 2010 | Alvin Ashcraft's Morning Dew — February 24, 2010 6:45 AM
    3. Thank you for submitting this cool story - Trackback from DotNetShoutout

      New in .NET 4: Don't Forget to Dispose() your SmtpClient Instances — February 24, 2010 7:24 AM
    4. Linked - List

      Linked - List — February 24, 2010 12:41 PM
    5. Pingback from The Morning Brew - Chris Alcock » The Morning Brew #547

      The Morning Brew - Chris Alcock » The Morning Brew #547 — February 25, 2010 2:34 AM
    6. .NET Pulse 3/3/2010

      .NET Pulse 3/3/2010 — March 3, 2010 10:30 AM
    Trackback link for this post:
    http://leedumond.com/trackback.ashx?id=86

    » Comments

    1. Jay Cincotta avatar

      Thanks for the tip!

      Jay Cincotta — February 23, 2010 11:07 PM
    2. Jannik avatar

      Wouldn't this be even better or more correct since SmtpClient can "span" multiple messages?:

      using (SmtpClient client = new SmtpClient())

      {

      using (MailMessage message = new MailMessage())

      {

      message.Subject = "Test Email";

      message.Body = "This is a test email from .NET 4!";

      message.To.Add("[email protected]");

      client.Send(message);

      }

      }

      Jannik — February 25, 2010 5:09 AM
    3. Visual C# Kicks avatar

      Thanks for the heads up

      Visual C# Kicks — February 25, 2010 2:44 PM
    4. Pankaj avatar

      I agree with Jannik's approach when we need to send to multiple recipients.

      Pankaj — February 25, 2010 4:25 PM
    5. Lee Dumond avatar

      For sure, if you're sending a bunch of emails, say newsletters or email alerts in some kind of a loop structure, then yes, obviously you wouldn't want to dispose SmtpClient until you're through with it. I was basically showing an implementation of sending a single mail, which is a lot more common scenario.

      Lee Dumond — February 25, 2010 4:41 PM
    6. Al Tenhundfeld avatar

      What analysis tool did you use?

      Al Tenhundfeld — February 26, 2010 9:11 AM
    7. Lee Dumond avatar

      Just the tool built in to VS 2010. I believe you only get that with Ultimate though. You could pretty much get the same functionality under VS Pro using FxCop though.

      Lee Dumond — February 26, 2010 9:39 AM
    8. andy avatar

      Doh, fails if I try to do this in .NET 3.5 meaning that my reusable email sending .NET library can't be corrct on both versions.

      'System.Net.Mail.SmtpClient': type used in a using statement must be implicitly convertible to 'System.IDisposable'

      andy — February 27, 2010 7:09 AM
    9. Lee Dumond avatar

      Right, this implementation is new to .NET 4.

      Lee Dumond — February 27, 2010 7:16 AM
    10. Jeff Tucker avatar

      I was the one that implemented that feature. Just so you know, smtpclient will also close your connections if you switch the host or port properties and then send another message. Glad you like this feature, I'm quite proud of it.

      Jeff Tucker — March 1, 2010 2:01 PM
    11. Bret Ferrier avatar

      I would like to second the way Jannik wrote the code

      Bret Ferrier — March 1, 2010 4:31 PM
    12. Paul Kohler avatar

      Nice heads up - would need to watch-out doing an update to v4...

      Paul Kohler — March 4, 2010 10:50 PM
    13. James Devlin avatar

      Thanks, I use this for auto-notify emails on my site. I'm still on 3.5 but I've added a TODO for 4.0.

      When's the book coming out? I've got about 200lbs of Wrox Press stuff.

      James Devlin — April 10, 2010 10:03 AM
    14. Lee Dumond avatar

      Thanks James.

      The book should be out sometime in the fall. I hope hope hope! By the way, it will be featuring WMD for markdown, which your blog turned me onto, so thanks much for that!

      Lee Dumond — April 10, 2010 10:41 AM
    15. James Radford, Web Developer avatar

      Thanks for the post, I'm investigating an issue with sending multiple emails out as I'm experiencing the 'An asynchronous call is already in progress' error with Log4Net...

      I'm going to try Jannik's suggestion so hopefully that resolves it! :)

      Thanks for the article!!

      James Radford, Web Developer — June 2, 2010 5:49 AM
    16. James Radford, Web Developer avatar

      just for completeness, if people are using Castle (castleproject.org) as I am in this case, the change to get this email working was more castle.configuration then writing new code... In this instance, I was able to modify the castle.configuration file to use the lifestyle="Transient" attribute for the EmailProvider component. 'Transient' allows the provider in this case the SMTP client to be instantiated per request... Fingers crossed that should do the trick.

      Cheers,

      James Radford, Web Developer — June 3, 2010 4:45 AM
    17. Galpones avatar

      Thanks for the post, this will be surely solving some of my issues.

      Galpones — June 15, 2010 6:44 PM
    18. Nikhil avatar

      Hi,

      Thats nice information.But what if we do not call dispose() method explecitly. I thought SmtpClient fall under managed code so CLR will take care of memory and instance.

      Nikhil — July 1, 2010 12:01 PM
    19. Mariscos avatar

      This is very intresting will test this method out.

      Mariscos — July 5, 2010 8:35 PM
    20. Wenfeng avatar

      Thanks for the post. I have a question. How to handle Dispose and SendAsync together?

      Fox example, I want to send a bunch of emails. Ideally, I'd use SendAsync and keep the connection open for better performance. I guess that I shouldn't call SmtpClient.Dispose after all the SendAsync calls, and I should call it in the last OnCompletion handler. How to handle this scenario?

      Thanks!

      Wenfeng — July 19, 2010 5:19 PM
    21. Rehabilitacion Fachadas Edificios avatar

      Try to shutoff the connection

      Rehabilitacion Fachadas Edificios — September 9, 2010 12:21 PM
    22. Vidhya avatar

      Thanks man, you made me learn something new. I was always using the second way.

      Any other idea to optimize async approach of sending email? my app. is sending 250 emails on avg. in 1 hour.

      Vidhya — September 18, 2010 9:27 AM
    23. Monica avatar

      My current code in production is doing something like this, but i am totally impressed by your way.

      My code looks like following, any suggestion to improve?

      //you require following name space

      using System.Net.Mail;

      //creating mail message object

      MailMessage mailMessage = new MailMessage();

      mailMessage.From = new MailAddress("Put From mail address here");

      mailMessage.To.Add(new MailAddress("Put To Email Address here"));

      mailMessage.CC.Add(new MailAddress("Put CC Email Address here"));

      mailMessage.Bcc.Add(new MailAddress("Put BCC Email Address here"));

      mailMessage.Subject = "Put Email Subject here";

      mailMessage.Body = "Put Email Body here ";

      mailMessage.IsBodyHtml = true;//to send mail in html or not

      SmtpClient smtpClient = new SmtpClient("Put smtp server host here", 25);//portno here

      smtpClient.EnableSsl = false; //True or False depends on SSL Require or not

      smtpClient.UseDefaultCredentials = true ; //true or false depends on you want to default credentials or not

      Object mailState = mailMessage;

      //this code adds event handler to notify that mail is sent or not

      smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);

      try

      {

      smtpClient.SendAsync(mailMessage, mailState);

      }

      catch (Exception ex)

      {

      Response.Write(ex.Message);

      Response.Write(ex.StackTrace);

      }

      Monica — October 26, 2010 3:50 PM
    24. Rune avatar

      One of my colleagues just told me that SmtpClient.Dispose() will fail miserably unless Host has been set.

      A quick glance using Reflector seems to confirm his diagnosis.

      transport.CloseIdleConnections(this.ServicePoint);

      looks dodgy, because ServicePoint checks if you've set host and port... D'oh!

      Rune — November 1, 2010 11:05 AM
    25. d2 avatar

      Thanks for this fix, really help me out.

      d2 — January 27, 2011 4:49 PM

    » Leave a Comment