我尝试一次向我的程序中的同一电子邮件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)
    {
    }
}

如何避免此错误?

我尝试一次向我的程序中的同一电子邮件ID发送300封邮件.我收到以下SMTP异常

这里的问题很可能是将相同的MailMessage实例传递给DispatchMailMailMessage在设计上不是线程安全的,每个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
}