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?
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:
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.