Jam*_*mes 6 c# multithreading smtp
我有一个控制台应用程序,可以向不同的收件人发送自定义的电子邮件(带附件),我想同时发送它们.我需要创建单独的SmtpClients来实现这一点,所以我使用QueueUserWorkItem来创建电子邮件并将它们发送到不同的线程中.
片段
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());
Run Code Online (Sandbox Code Playgroud)
我已经注意到(间歇性地)有时并非所有电子邮件都使用上述代码到达特定邮箱.我原以为使用Send
over SendAsync
意味着电子邮件肯定是从应用程序发送的.但是,在行之后添加以下代码WaitHandle.WaitAll
行:
System.Threading.Thread.Sleep(5000);
Run Code Online (Sandbox Code Playgroud)
似乎工作.我的想法是,无论出于何种原因,仍然没有发送一些电子邮件(即使在Send
方法运行之后).给予额外的5秒似乎给应用程序足够的时间来完成.
这可能是我等待发送电子邮件的方式的问题吗?或者这是实际Send方法的问题?一旦我们通过这条线,电子邮件肯定是从应用程序发送的吗?
任何有关此问题的想法都会很棒,似乎无法完全理解实际原因.
更新
这里要求的是SMTP代码:
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();
}
Run Code Online (Sandbox Code Playgroud)
你的代码让我烦恼的事情之一是你events.Add
在线程方法中调用。该类Dictionary<TKey, TValue>
不是线程安全的;这段代码不应该在线程内部。
更新:我认为 ChaosPandion 发布了一个很好的实现,但我会让它变得更简单,这样在线程安全方面就不会出错:
var events = new List<AutoResetEvent>();
foreach (...)
{
var evt = new AutoResetEvent();
events.Add(evt);
var alert = CreateAlert(...);
ThreadPool.QueueUserWorkItem(delegate
{
alert.Send();
evt.Set();
});
}
// wait for all emails to signal
WaitHandle.WaitAll(events.ToArray());
Run Code Online (Sandbox Code Playgroud)
我在这里完全消除了字典,并且所有实例AutoResetEvent
都是在稍后执行WaitAll
. 如果此代码不起作用,则一定是电子邮件本身有问题;服务器正在丢弃消息(您发送了多少条消息?),或者您试图在实例之间共享非线程安全的内容Alert
(可能是单例或静态声明的内容)。