SmtpClient very slow - about 2 seconds to send one very small email

16,388

Solution 1

The SmtpClient class I believe does not reuse the same connection for each mail sent (edit: apparently this is now possible in .NET 4.0, see the differences in documentation for SmtpClient). Opening a new connection is expensive, and that is probably what takes time. There are commercial SMTP components that do and offer much higher performance. Depending on SMTP server and mail size, it is possible to achieve something like at least 50mails/second.

However this might not be an issue for you if you change the architecture slightly. What I do in my application is that SmtpClient delivers mails to a folder, by using smtpClient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory and setting the PickupDirectoryLocation to the wanted directory. What this does is, instead of sending the mail messages over the network, it will write them to the specified folder as standard mime messages (.eml format).

Here you can either use the IIS SMTP server or simply make another background thread/process to consume the .eml files created and deliver them to the recipients or to another SMTP server.

This approach I think is much superior, simply because:

  • The client code sending the mail never has to wait for the actual mail to be sent, which can take a fair while depending on connection speed, latency etc.
  • If the mail sent did not succeed, the client code is not affected. The mail can be sent some other time in the background.
  • The mail queue is persistent, if the application is stopped and started again, mails in the queue will not be lost.
  • Easier for testing purposes.

As a simpler approach, you can use SendAsync instead of Send, but it doesn't give all the immediate approaches the PickupDirectory approach will give.

Solution 2

Speed of SmtpClient class is mostly dependent on the SMTP server that you're connecting to & your internet connection speed. The best way to optimize your through-output using SmtpClient.SendAsync and creating up to 10 or more streamlined connections to the smtp server. After all, this is same strategy of all the modern web browsers do to speed up browsing.

Solution 3

A few things come to mind.

First off, some sites will purposely slow down the connection in order to make it less profitable for spammers to send mail to their systems. This is called Tarpitting.

Interestingly, the mail server your site uses to broadcast out might even have this turned on. ( http://winzenz.blogspot.com/2005/12/enabling-smtp-tarpitting-in-windows.html )

Other things that might cause issues is if the receiving mail server has a short TTL for it's DNS settings and/or YOUR web server has some bad (e.g. dead or overloaded) DNS servers in it's IP setup.

Share:
16,388
Ted
Author by

Ted

Been programming since around the year 2000 where I started out with C# and PHP for different projects, and since quickly learned to love .NET and C#, which has grown from good to GREAT. Have dabbled with JAVA, Java for Android, PHP, JS, CSS, HTML, but C# is my thing.

Updated on June 04, 2022

Comments

  • Ted
    Ted almost 2 years

    I'm using SmtpClient to send a simple email.

    The email consists of about 25 plaintext characters so it's small.

    It however takes the SmtpClient about 2000 milliseconds to send one of them. I do not create the SmtpClient for each send - that is created on program start so the only thing that is done is this:

    DateTime start = DateTime.Now;
    
    MailMessage oMsg = new MailMessage();
    // TODO: Replace with sender e-mail address.
    oMsg.From = new MailAddress(settings._Username);
    oMsg.To.Add(new MailAddress(emailEvent._ContactItemToUse.Data));
    oMsg.Subject = emo._Subject;
    oMsg.BodyEncoding = Encoding.UTF8;
    oMsg.IsBodyHtml = emo._IsHtmlText;
    oMsg.Body = emo._Text;
    client.Send(oMsg);
    TimeSpan timeWasted = DateTime.Now.Subtract(start); // between 1000-2000 ms
    

    This is of course very bad, and I can't figure out why. Can I improve it?

  • Ted
    Ted about 13 years
    Its actually our own smtp server. I will take a look at that
  • Ted
    Ted about 13 years
    The sendAsync is sort of stupid I think. I get an error saying "an async call is being processed yada yada, you have to wait until that finishes"
  • Teoman Soygul
    Teoman Soygul about 13 years
    You'll need to create separate SmtpClient object for each async call. i.e. a List<SmtpClient> clients; where you can monitor the state of each client and reuse the clients when they finish up sending the mail. This will consume a lot of memory though. – Teoman Soygul 7 mins ago
  • Ted
    Ted about 13 years
    Thanks for the tip! I realized that we are in fact not using our own mailserver. if we do, the file thing might be a way to go. However, it is not the reuse or not reuse of the client that is the bad guy here. I tried both, and if I reuse of not reuse it still takes 1-2 seconds.
  • Can Gencer
    Can Gencer about 13 years
    @Ted, which framework version are you using? It seems to me that SmtpClient did not reuse connections before .NET 4.0, looking at the MSDN documentation. Myself I've avoided SmtpClient except to write to a folder, and use an actual commercial component instead for the delivery, as SmtpClient lacks a lot of features.
  • Chris
    Chris about 10 years
    In my case it was simply the server being slow. We switched from using our exchange server (which none of us have the experience to troubleshoot) to a local SMTP server and now everything's super fast. No code changes necessary.