两种通过SmtpClient异步发送电子邮件的方式,结果不同

这里简单的概念。 这适用于使用MVC 3和Entity Framework 4构建的站点。用户在站点上注册后,会向其电子邮件地址发送一封电子邮件。 我首先使用SmtpClient.Send()实现它,它工作正常。 然后我明白了尝试异步发送电子邮件。 我遇到了我尝试过的两种异步方法的问题。

首次实施(来自这篇未回答的post: https : //stackoverflow.com/questions/7558582/how-to-dispose-using-smtpclient-send-and-asynccallback ):

public bool Emailer(){ . . . using (var smtpClient = new SmtpClient()) { smtpClient.EnableSsl = true; smtpClient.Host = "smtp.gmail.com"; smtpClient.Port = 587; smtpClient.UseDefaultCredentials = false; smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword"); var sd = new SendEmailDelegate(smtpClient.Send); var cb = new AsyncCallback(SendEmailResponse); sd.BeginInvoke(message, cb, sd); return true; } } private delegate void SendEmailDelegate(System.Net.Mail.MailMessage m); private static void SendEmailResponse(IAsyncResult ar) { try { SendEmailDelegate sd = (SendEmailDelegate)(ar.AsyncState); sd.EndInvoke(ar); // "cannot access a disposed object" errors here } catch (Exception e) { _logger.WarnException("Error on EndInvoke.", e); } } 

这有一半的时间。 另一半我会在CallBack中得到“无法访问已处置对象”错误。

下一个实现(来自具有良好声誉的成员: 在.NET 4.0下使用SmtpClient,SendAsync和Dispose的最佳实践是什么 ):

 var smtpClient = new SmtpClient(); smtpClient.EnableSsl = true; smtpClient.Host = "smtp.gmail.com"; smtpClient.Port = 587; smtpClient.UseDefaultCredentials = false; smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword"); smtpClient.SendCompleted += (s, e) => { smtpClient.Dispose(); message.Dispose(); }; smtpClient.SendAsync(message, null); 

有了这个实现,我没有得到任何错误,但是当smtpClient.SendAsync()执行时,在调试模式下有明显更长的延迟(~5秒),这使我认为它不是异步发送的。

问题:

1)导致“处置对象”错误的第一种方法出了什么问题?

2)第二个实现是否存在导致电子邮件不能异步发送的问题? 5秒延迟是无意义的吗?

可能还需要注意的是,虽然该网站不需要支持发送大量电子邮件(仅限用户注册,选择加入新闻通讯等),但我们预计将来会有大量用户,因此我决定异步发送电子邮件。

谢谢。

由于USING-block,你的第一种方法无法正常工作。 使用块结束后,SmtpClient对象将被释放。 因此,您无法在事件处理程序中访问它。

提示:1 – 不要对MailMessage对象使用“使用块”,它会在邮件发送之前处理您的对象
2在SmtpClient.SendCompleted事件上配置MailMessage对象:

 smtpClient.SendCompleted += (s, e) => { message.Dispose(); }; 

用于smtpClient对象的3组SendCompletedEventHandler

 smtpClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback); 

4个代码:

 private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) { // Get the unique identifier for this asynchronous operation. String token = (string)e.UserState; if (e.Cancelled) { //write your code here } if (e.Error != null) { //write your code here } else //mail sent { //write your code here } mailSent = true; } 

SmtpClient.SendAsync是异步电子邮件发送的首选方法,因为它使用专门为此目的设计的SmtpClient方法。 它实现起来也更简单,并且已被certificate可以工作数千次。

你的5秒延迟是奇怪的,并表明存在需要解决的问题。 第一段代码只是解决问题,但并没有消除它。

如果您的传递方法不是 SpecifiedPickupDirectoryPickupDirectoryFromIis SmtpClient.SendAsync实际上只会异步发送。 在这些情况下,它会在返回之前将消息文件写入拾取文件夹。 检查配置文件的部分。 我的猜测是你正在使用其中一种方法,问题在于拾取文件夹。 删除您可能在那里的旧文件,并检查问题是否是您的防病毒软件,它很可能会搜索每个新文件中的病毒。 检查是否设置了加密或压缩属性。 也可以是别的东西。 测试文件夹是否是问题根源的最佳方法是手动将电子邮件文件复制到其中。