【问题标题】:Need to send email using background worker process需要使用后台工作进程发送电子邮件
【发布时间】:2011-07-11 16:02:48
【问题描述】:

我用 C# 编写了用于发送电子邮件的代码,但是当应用程序发送的附件大小超过 2 MB 的邮件时,应用程序挂起。 SO用户建议我使用后台工作进程。

我已经浏览了 MSDN 中的后台工作进程示例,也通过谷歌搜索过,但我不知道如何集成到我的代码中。

请指导我...

谢谢

更新:添加了电子邮件代码

public static void SendMail(string fromAddress, string[] toAddress, string[] ccAddress, string[] bccAddress, string subject, string messageBody, bool isBodyHtml, ArrayList attachments, string host, string username, string pwd, string port)
{
  Int32 TimeoutValue = 0;
  Int32 FileAttachmentLength = 0;
  {
    try
    {
      if (isBodyHtml && !htmlTaxExpression.IsMatch(messageBody))
        isBodyHtml = false;
      // Create the mail message
      MailMessage objMailMsg;
      objMailMsg = new MailMessage();
      if (toAddress != null) {
        foreach (string toAddr in toAddress)
          objMailMsg.To.Add(new MailAddress(toAddr));
      }
      if (ccAddress != null) {
        foreach (string ccAddr in ccAddress)
          objMailMsg.CC.Add(new MailAddress(ccAddr));
      }
      if (bccAddress != null) {
        foreach (string bccAddr in bccAddress)
          objMailMsg.Bcc.Add(new MailAddress(bccAddr));
      }
      if (fromAddress != null && fromAddress.Trim().Length > 0) {
        //if (fromAddress != null && fromName.trim().length > 0)
        //    objMailMsg.From = new MailAddress(fromAddress, fromName);
        //else
        objMailMsg.From = new MailAddress(fromAddress);
      }
      objMailMsg.BodyEncoding = Encoding.UTF8;
      objMailMsg.Subject = subject;
      objMailMsg.Body = messageBody;
      objMailMsg.IsBodyHtml = isBodyHtml;
      if (attachments != null) {
        foreach (string fileName in attachments) {
          if (fileName.Trim().Length > 0 && File.Exists(fileName)) {
             Attachment objAttachment = new Attachment(fileName);
             FileAttachmentLength=Convert.ToInt32(objAttachment.ContentStream.Length);
             if (FileAttachmentLength >= 2097152) {
               TimeoutValue = 900000;
             } else {
                TimeoutValue = 300000;
             }
             objMailMsg.Attachments.Add(objAttachment);
             //objMailMsg.Attachments.Add(new Attachment(fileName)); 
           }
        }
      }
      //prepare to send mail via SMTP transport
      SmtpClient objSMTPClient = new SmtpClient();
      if (objSMTPClient.Credentials != null) { } else {
        objSMTPClient.UseDefaultCredentials = false;
        NetworkCredential SMTPUserInfo = new NetworkCredential(username, pwd);
        objSMTPClient.Host = host;
        objSMTPClient.Port = Int16.Parse(port);
        //objSMTPClient.UseDefaultCredentials = false;
        objSMTPClient.Credentials = SMTPUserInfo;
        //objSMTPClient.EnableSsl = true;
        //objSMTPClient.DeliveryMethod = SmtpDeliveryMethod.Network;
      }
      //objSMTPClient.Host = stmpservername;
      //objSMTPClient.Credentials
      //System.Net.Configuration.MailSettingsSectionGroup mMailsettings = null;
      //string mailHost = mMailsettings.Smtp.Network.Host;
      try {
        objSMTPClient.Timeout = TimeoutValue;
        objSMTPClient.Send(objMailMsg);
        //objSMTPClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
        objMailMsg.Dispose();
      }
      catch (SmtpException smtpEx) {
        if (smtpEx.Message.Contains("secure connection")) {
           objSMTPClient.EnableSsl = true;
           objSMTPClient.Send(objMailMsg);
        }
      }
    }
    catch (Exception ex)
    {
       AppError objError = new AppError(AppErrorType.ERR_SENDING_MAIL, null, null, new AppSession(), ex);
       objError.PostError();
       throw ex;
    }
  }
}

我无法在此处修改代码,因为这是从我的应用程序发送邮件时调用的常用方法。

【问题讨论】:

  • 如果你能提供你当前的代码会很有帮助。我们可以将其转换为背景,而不是我们提供一个您可能不理解如何融入您的代码的示例。
  • @Fun Mun Pieng:我已经添加了代码..

标签: c# winforms multithreading smtp backgroundworker


【解决方案1】:

Richard Kiessig 的“Ultra-Fast ASP.NET”一书的第 8 章中有一个很好的例子来说明如何使用“服务代理”来做到这一点。

这是出版商网站上该书的链接,您可以从该链接下载该书的示例代码。再说一遍,第 8 章……

http://apress.com/book/view/9781430223832

【讨论】:

  • 使用 Service Broker 发送电子邮件的优点是请求是持久的,因此它们在 AppPool 重新启动后仍然存在,并且如果需要,可以将任务移动到单独的服务器,以确保安全和/或可扩展性的原因。
【解决方案2】:

您可以启动一个后台线程来不断循环和发送电子邮件:

private void buttonStart_Click(object sender, EventArgs e)
{
    BackgroundWorker bw = new BackgroundWorker();
    this.Controls.Add(bw);
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerAsync();
}

private bool quit = false;
void bw_DoWork(object sender, DoWorkEventArgs e)
{
    while (!quit)
    {
        // Code to send email here
    }
}

另一种方法:

private void buttonStart_Click(object sender, EventArgs e)
{
    System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
    client.SendCompleted += new System.Net.Mail.SendCompletedEventHandler(client_SendCompleted);
    client.SendAsync("from@here.com", "to@there.com", "subject", "body", null);
}

void client_SendCompleted(object sender, AsyncCompletedEventArgs e)
{
    if (e.Error == null)
        MessageBox.Show("Successful");
    else
        MessageBox.Show("Error: " + e.Error.ToString());
}

具体到您的示例,您应该替换以下内容:

try
{
    objSMTPClient.Timeout = TimeoutValue;
    objSMTPClient.Send(objMailMsg);
    //objSMTPClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
    objMailMsg.Dispose();
}
catch (SmtpException smtpEx)
{
    if (smtpEx.Message.Contains("secure connection"))
    {
        objSMTPClient.EnableSsl = true;
        objSMTPClient.Send(objMailMsg);
    }
}

以下内容:

objSMTPClient.Timeout = TimeoutValue;
objSMTPClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
objSMTPClient.SendAsync(objMailMsg, objSMTPClient);

再往下,包括:

void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
    if (e.Error == null)
        MessageBox.Show("Successful");
    else if (e.Error is SmtpException)
    {
        if ((e.Error as SmtpException).Message.Contains("secure connection"))
        {
            (e.UserState as SmtpClient).EnableSsl = true;
            (e.UserState as SmtpClient).SendAsync(objMailMsg, e.UserState);
        }
        else
            MessageBox.Show("Error: " + e.Error.ToString());
    }
    else
        MessageBox.Show("Error: " + e.Error.ToString());
}

【讨论】:

  • 感谢输入。所以这段代码不需要包含任何后台进程?我也没有在智能感知中获得 AsyncCompletedEventArgs。这可能是什么原因?
  • 添加using System.ComponentModel;或更改为System.ComponentModel.AsyncCompletedEventArgs
  • 再次感谢您的输入。最后评论有效!但是电子邮件没有发送。不知道为什么..
  • @Xor power,我不确定您是否应该处理您的消息。我没有检查 SendAsync 是否真的制作了消息的副本或使用您的副本。如果它使用您的副本并且您调用 dispose,我想一段时间后会引发异常并且邮件将失败。如果它制作副本,那么将没有问题。请尝试一下,看看会发生什么。
猜你喜欢
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 2013-10-01
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-28
  • 2015-08-07
相关资源
最近更新 更多