I have a console application that sends customized emails (with attachments) to different recipients and I want to send them concurrently. I need to create separate SmtpClients to achieve this so I am using QueueUserWorkItem to create the emails and send them in separate threads.
Snippet
var events = new Dictionary<Guid, AutoResetEvent>();
foreach (...)
{
ThreadPool.QueueUserWorkItem(delegate
{
var id = Guid.NewGuid();
events.Add(id, new AutoResetEvent(false));
var alert = // create custom class which internally creates SmtpClient & Mail Message
alert.Send();
events[id].Set();
});
}
// wait for all emails to signal
WaitHandle.WaitAll(events.Values.ToArray());
I have noticed (intermittently) that sometimes not all the emails arrive in the specific mailboxes with the above code. I would have thought that using Send
over SendAsync
would mean the email has definitely sent from the application. However, adding the following line of code after the WaitHandle.WaitAll
line:
System.Threading.Thread.Sleep(5000);
Seems to work. My thinking is, for whatever reason, some emails still haven't been sent (even after the Send
method has run). Giving those extra 5 seconds seems to give the application enough time to finish.
Is this perhaps an issue with the way I am waiting on the emails to send? Or is this an issue with the actual Send method? Has the email definitely been sent from the app once we pass this line?
Any thoughts idea's on this would be great, can't quite seem to put my finger on the actual cause.
Update
As requested here is the SMTP code:
SmtpClient client = new SmtpClient("Host");
FieldInfo transport = client.GetType().GetField("transport", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo authModules = transport.GetValue(client).GetType()
.GetField("authenticationModules", BindingFlags.NonPublic | BindingFlags.Instance);
Array modulesArray = authModules.GetValue(transport.GetValue(client)) as Array;
modulesArray.SetValue(modulesArray.GetValue(2), 0);
modulesArray.SetValue(modulesArray.GetValue(2), 1);
modulesArray.SetValue(modulesArray.GetValue(2), 3);
try
{
// create mail message
...
emailClient.Send(emailAlert);
}
catch (Exception ex)
{
// log exception
}
finally
{
emailAlert.Dispose();
}