2

The MSDN docs for SmptClient say that instance members are not guaranteed to be thread-safe (born out by the use of instance properties to store things like the MailWriter in the reference source).

On the other hand, this post (and my experience) suggests that simply creating and disposing an SmtpClient for each email sent can cause you to hit the connection limit pretty easily.

What's the best way to manage these objects? Do I have to manually create a pool or throttle usage with a semaphore? Or, is there some easier pattern to follow. I'm always using the same mail server.

Community
  • 1
  • 1
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
  • are you sending a few emails at a time or hundreds (or more)? I've used queues to store the message and have a separate service pick up the messages and send them out via a mail service – EdmundYeung99 Jun 10 '15 at 20:45
  • Don't access them from multiple threads. Tada. If you need to, cache your emails and have a worker flush the cache every X minutes. Double tada. Last thing, harden the cache against application restarts. The Aristocrats. –  Jun 10 '15 at 21:22

3 Answers3

1

I would recommend using a persistent MessageQueue such as RabbitMQ to send an event along with a payload to that queue. I will write a consumer to read off that queue, and send it to an email service that will handle the sending, logging, and raising additional email events that you may want to track for BI reasons.

That being said, if you are sending in thousands of emails per day, you will need to certify your IP address for sending such load. This process takes a long time, but once that IP is certified, you should experience no issues.

AL-Tamimi
  • 672
  • 5
  • 9
1

Don't reinvent the tools that you already have available. Look at the DeliveryMethod property for the SmtpClient class. One of the options is to have the messages automatically queue up for you and delivered in the background via the Microsoft SMTP Service. Set the DeliveryMethod to PickupDirectoryFromIis and the messages will be written to the queue mail folder as fast as you can generate them. Then all you have to do is configure the Microsoft SMTP Server to forward the outgoing mail to a local mail server and you are done. If you look for references to the older CDOSYS methods using the mail pickup option, this works exactly the same way.

dmarietta
  • 1,940
  • 3
  • 25
  • 32
  • Do you mean PickupDirectoryFromIis? Also, if you are using this method, how do you handle your SmtpClient objects? New one each time and dispose? – ChaseMedallion Jun 11 '15 at 12:37
  • @ChaseMedallion Correct, I edited to fix the typo above. Yes, using it this way, your calls to SmtpClient are simply writing to the local filesystem queue. This removes any such issues and stops blocking due to network connection activity to the destination mail server which would now be occurring asynchronously from your code on a completely separate process. – dmarietta Jun 11 '15 at 15:20
0

The posts are indeed on the right track, created a SmtpClient object for every email you send is not the right approach. What I have done is setup a Queue. I have then started a thread which listens for any messages on the queue and sends them off using the same SmtpClient instance. The pseudo-code would be:

while (queue.HasEmails)
{
    SendEmail()
}
WaitForAFlag // So we don't keep spinning

Everytime an item is added to the queue you simply SetTheFlag so the thread will start reading the queue again.

Ruskin
  • 1,504
  • 13
  • 25