我尝试一次向我的程序中的同一电子邮件ID发送300封邮件.我收到以下SMTP异常
本文关键字:发送 SMTP 异常 ID 一次 程序 我的 电子邮件 | 更新日期: 2023-09-27 18:31:34
错误: System.Net.Mail.Smtp异常: 发送邮件失败。 ---> System.ArgumentException: IAsyncResult 对象未从此类上的相应异步方法返回。 参数名称:asyncResult at System.Net.Mime.MimeBasePart.EndSend(IAsyncResult asyncResult) at System.Net.Mail.Message.EndSend(IAsyncResult asyncResult) at System.Net.Mail.SmtpClient.SendMessageCallback(IAsyncResult result) --- 内部异常堆栈跟踪---结束
private void DispatchMail(MailMessage message, MessageTrackerObject trackInfo)
{
SmtpClient mailClient = new SmtpClient();
mailClient.Host = ConfigurationManager.AppSettings[(Constants.FAXSETTINGS_SMTPSERVER)];
mailClient.Port = int.Parse(ConfigurationManager.AppSettings[(Constants.FAXSETTINGS_SMTPPORT)]);
//mailClient.DeliveryMethod = SmtpDeliveryMethod.Network;
NetworkCredential ntCredential = new NetworkCredential();
if (GetStaticSetting(Constants.APPCONFIG_KEY_MAILWINDOWSAUTH).ToLower() == "true")
{
//mailClient.UseDefaultCredentials = true;
}
else
{
ntCredential.UserName = GetStaticSetting(Constants.APPCONFIG_KEY_MAILUSERID);
ntCredential.Password = GetStaticSetting(Constants.APPCONFIG_KEY_MAILPASSWORD);
mailClient.Credentials = ntCredential;
mailClient.UseDefaultCredentials = false;
}
mailClient.EnableSsl = GetStaticSetting(Constants.APPCONFIG_KEY_MAIL_SSL).ToLower() == "true";
mailClient.SendCompleted += new SendCompletedEventHandler(MailClient_SendCompleted);
mailClient.SendAsync(message, trackInfo);
//mailClient.Send(message);
}
private void MailClient_SendCompleted(object sender, AsyncCompletedEventArgs e)
{
string error = "";
MessageTrackerObject data = (MessageTrackerObject)e.UserState;
string msg = string.Format("File: {0}", data.Info);
try
{
foreach (string serial in data.Serials)
{
if (e.Cancelled)
{
error = e.Error != null ? String.Format(" #Error: {0}", e.Error.ToString()) : "";
string cancelled = string.Format("{0} Send canceled. {1}", msg, error);
SetFaxStatus(serial, FaxStatus.Cancelled, cancelled);
}
else if (e.Error != null)
{
error = String.Format("{0} #Error: {1}", msg, e.Error.ToString());
SetFaxStatus(serial, FaxStatus.Error, error);
}
else
{
SetFaxStatus(serial, FaxStatus.Sent, string.Format("{0} Mail sent successfully.", msg));
}
}
//release resource
data.Message.Dispose();
}
catch (Exception ex)
{
}
}
如何避免此错误?
这里的问题很可能是将相同的MailMessage
实例传递给DispatchMail
。 MailMessage
在设计上不是线程安全的,每个SmtpClient.SendAsync
都在内部调用Message.BeginSend
。
因此,当多个线程尝试发送相同的MailMessage
时,调用Message.EndSend
时会出现争用条件。如果EndSend
由调用BeginSend
的同一线程调用 - 我们很幸运。如果没有 - 引发上面的异常,
未从相应的 此类上的异步方法
这里的解决方案是为每个调用SendAsync
复制MailMessage
,或者使用接受 5 个参数SendAsync
重载:
void SendAsync(string from, string recipients, string subject, string body, object token)
编辑:此异常很容易重现,以证明 MailMessage 不是线程安全的。您可能会遇到几个异常,IAsyncResult
上面的一个,或者在填充标头时Item has already been added
:
using System;
using System.Net.Mail;
using System.Threading.Tasks;
class App
{
static void Main()
{
var mail = new MailMessage("aaa@bbb.ccc", "ddd@eee.fff", "Test Subj", "Test Body");
var client1 = new SmtpClient("localhost");
var client2 = new SmtpClient("localhost");
var task1 = client1.SendMailAsync(mail);
var task2 = client2.SendMailAsync(mail);
Task.WhenAll(task1, task2).Wait();
}
}
使用 ManualResetEvent
对象。我猜SmtpClient正在被处置,这就是为什么它失去了对MailClient_SendCompleted
的订阅
ManualResetEvent resetEvent;
private void DispatchMail(MailMessage message, MessageTrackerObject trackInfo)
{
// other code here
resetEvent = new ManualResetEvent(false);
mailClient.EnableSsl = GetStaticSetting(Constants.APPCONFIG_KEY_MAIL_SSL).ToLower() == "true";
mailClient.SendCompleted += new SendCompletedEventHandler(MailClient_SendCompleted);
mailClient.SendAsync(message, trackInfo);
resetEvent.WaitOne(TimeSpan.FromSeconds(5)); // waits for 5 seconds
//mailClient.Send(message);
}
private void MailClient_SendCompleted(object sender, AsyncCompletedEventArgs e)
{
resetEvent.Set(); // removes the wait after successfully sending
string error = "";
MessageTrackerObject data = (MessageTrackerObject)e.UserState;
// other code here
}