Skip to main content
 首页 » 编程设计

c#之在 SendCompleted 事件中重新发送电子邮件

2024年02月13日29落叶无声

我有一个名为 SchedulerService 的类,其中有一个 SendMail 函数,当需要在特定时间发送电子邮件时调用该函数。当我调用 SendMail 函数时,我传入了一个对象,该对象包含有关将电子邮件发送给谁以及电子邮件来自谁的信息。现在,我添加了一个 SendCompleted 处理程序,以便我可以重新发送电子邮件,以防万一发生导致它无法发送的情况。我有发送邮件的代码:

    var recipients = EmailTo.Split(',').ToList(); 
    if (String.IsNullOrEmpty(EmailFrom)) 
        EmailFrom = recipients[0]; 
 
    using (MailMessage message = new MailMessage()) 
      { 
        message.From = new MailAddress(EmailFrom); 
        recipients.ForEach(a => message.To.Add(new MailAddress(a))); 
        message.Attachments.Add(new Attachment(LocationOfResults)); 
        message.Subject = String.Format("{0:MM-dd-yyyy} Results for task: {1}.", DateTime.Now, Description); 
        message.Body = "Attached is the results file specified for the task: " + Description; 
        smtpClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback); 
        smtpClient.UseDefaultCredentials = true; 
        smtpClient.SendAsync(message, null); 
 
                } 

这是事件处理器

    private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) 
    { 
        if (e.Cancelled) 
        { 
            MailMessage mail = (MailMessage)e.UserState; 
            using (mail) 
            { 
                 smtpClient.Send(mail); 
            } 
        } 
        if (e.Error != null) 
        { 
            Log(e.Error.ToString() + " in SendCompletedHandlerEvent", EventLogEntryType.Error); 
        } 
 
    } 

问题是,我发现这样做是行不通的,因为“收件人”和“发件人”字段是空的,这会在发送电子邮件时导致错误。我应该如何从发送失败的电子邮件中回收收件人/发件人字段?

请您参考如下方法:

如果你想使用异步发送,那么你应该摆脱 using block ,它会处理你初始化的 message 变量。相反,您可以从 SendCompleted 事件处理程序调用 Dispose() 或仅从初始化方法调用 Dispose:

 /*...*/ 
 smtpClient.SendAsync(message, null); 
 message.Dispose(); 

您也可以在 this page 上找到这种方法MSDN

此外,您应该以某种方式重写您的初始化,使其看起来像这样:

smtpClient.Credentials = new NetworkCredential("somemail@gmail.com", "pass"); 
            smtpClient.Port = 587; 
            smtpClient.Host = "smtp.gmail.com"; 
            smtpClient.SendAsync(message, null); 
            smtpClient.SendCompleted  += new SendCompletedEventHandler(smtpClient_SendCompleted); 

也就是说,我的意思是 SendAsync 和 Credentails 以及执行操作所需的其他参数应该首先设置。

UPD 它将解决处理原始 message 变量的问题,这就是为什么“To 和 From 字段为空”的原因。

关于重新发送 - 请提供更多代码或情况示例,无论您将如何以及在哪里避免消息发送取消和重新发送。

另外,取消消息重发到底是什么意思?您想再次发送已取消的消息是否正确?据我了解,您无法继续发送在您的情况下使用 SendAsyncCancel() 取消的消息。

在执行 SendAsyncCancel 的情况下,它仍然会引发 SendCompleted 事件,但传递的参数表明操作已取消。所以,你无法逃避它。你可能想看看 this page ,当然还有 MSDN。

如果您需要发送这么多消息,以防万一出现取消发送的问题,请重新发送:

  /*your SendCompleted EventHandler*/ 
 if (e.Canceled) 
  { 
    //if you use using(message) {...} here, you'll get ObjectDisposedException again 
   SmtpClient smtp; 
    smtp = new SmtpClient();   
     smtp = GetClient(smtp);  //method of your smtpClient initialization 
    MailMessage mess = new MailMessage(); 
    mess = GetMessage(mess, smtp);  //method of your mailMessage initialization 
 
    try 
    { 
        //sending message again 
        smtp.SendAsync(mess, null); 
 
    } 
    catch (ObjectDisposedException e) 
    { 
       MessageBox.Show("The email message was not sent. See the details:\n"+e.Message, 
      "Error sendiing message") 
 
     } 
  } 

我使用 SendAsyncCancel 方法对其进行了测试,因此我希望考虑到大部分取消原因。