2008-11-11 126 views
30

我正在通过ASP.NET MVC使用服务组件。 我想以异步的方式发送电子邮件,让用户无需等待发送即可完成其他任务。如何使用SmtpClient.SendAsync发送带有附件的电子邮件?

当我发送没有附件的消息时,它工作正常。 当我发送带有至少一个内存附件的消息时,它会失败。

所以,我想知道是否有可能使用内存附件的异步方法。

这里是发送方法


    public static void Send() { 

     MailMessage message = new MailMessage("[email protected]", "[email protected]"); 
     using (MemoryStream stream = new MemoryStream(new byte[64000])) { 
      Attachment attachment = new Attachment(stream, "my attachment"); 
      message.Attachments.Add(attachment); 
      message.Body = "This is an async test."; 

      SmtpClient smtp = new SmtpClient("localhost"); 
      smtp.Credentials = new NetworkCredential("foo", "bar"); 
      smtp.SendAsync(message, null); 
     } 
    } 

这里是我当前的错误


System.Net.Mail.SmtpException: Failure sending mail. 
---> System.NotSupportedException: Stream does not support reading. 
    at System.Net.Mime.MimeBasePart.EndSend(IAsyncResult asyncResult) 
    at System.Net.Mail.Message.EndSend(IAsyncResult asyncResult) 
    at System.Net.Mail.SmtpClient.SendMessageCallback(IAsyncResult result) 
    --- End of inner exception stack trace --- 

解决方案

public static void Send() 
    { 

      MailMessage message = new MailMessage("[email protected]", "[email protected]"); 
      MemoryStream stream = new MemoryStream(new byte[64000]); 
      Attachment attachment = new Attachment(stream, "my attachment"); 
      message.Attachments.Add(attachment); 
      message.Body = "This is an async test."; 
      SmtpClient smtp = new SmtpClient("localhost"); 
      //smtp.Credentials = new NetworkCredential("login", "password"); 

      smtp.SendCompleted += delegate(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
      { 
        if (e.Error != null) 
        { 
          System.Diagnostics.Trace.TraceError(e.Error.ToString()); 

        } 
        MailMessage userMessage = e.UserState as MailMessage; 
        if (userMessage != null) 
        { 
          userMessage.Dispose(); 
        } 
      }; 

      smtp.SendAsync(message, message); 
    } 

回答

33

“使用” 这里不要使用。您在调用SendAsync后立即销毁内存流,例如可能在SMTP读取它之前(因为它是异步)。在回调中销毁您的流。

0

我已经试过你的功能和它的作品甚至电子邮件在内存附件。但是这里有一些评论:

  • 你尝试发送什么类型的附件?可执行程序 ?
  • 发送者和接收者都在同一个电子邮件服务器上吗?
  • 你应该“捕捉”异常,而不是只是吞下它,比你会得到更多关于你的问题的信息。
  • 这个例外是什么意思?

  • 是否可以使用Send而不是SendAsync?您在发送电子邮件之前使用'使用'条款并关闭Stream。

下面是关于这个话题好文:

Sending Mail in .NET 2.0

+0

我应该放更多的代码,对不起。 让我编辑示例给你更多的信息。 – labilbe 2008-11-12 01:45:01

0

对原始问题中提供的解决方案的扩展还正确地清理了可能还需要处置的附件。

public event EventHandler EmailSendCancelled = delegate { }; 

    public event EventHandler EmailSendFailure = delegate { }; 

    public event EventHandler EmailSendSuccess = delegate { }; 
    ... 

     MemoryStream mem = new MemoryStream(); 
     try 
     { 
      thisReport.ExportToPdf(mem); 

      // Create a new attachment and put the PDF report into it. 
      mem.Seek(0, System.IO.SeekOrigin.Begin); 
      //Attachment att = new Attachment(mem, "MyOutputFileName.pdf", "application/pdf"); 
      Attachment messageAttachment = new Attachment(mem, thisReportName, "application/pdf"); 

      // Create a new message and attach the PDF report to it. 
      MailMessage message = new MailMessage(); 
      message.Attachments.Add(messageAttachment); 

      // Specify sender and recipient options for the e-mail message. 
      message.From = new MailAddress(NOES.Properties.Settings.Default.FromEmailAddress, NOES.Properties.Settings.Default.FromEmailName); 
      message.To.Add(new MailAddress(toEmailAddress, NOES.Properties.Settings.Default.ToEmailName)); 

      // Specify other e-mail options. 
      //mail.Subject = thisReport.ExportOptions.Email.Subject; 
      message.Subject = subject; 
      message.Body = body; 

      // Send the e-mail message via the specified SMTP server. 
      SmtpClient smtp = new SmtpClient(); 
      smtp.SendCompleted += SmtpSendCompleted; 
      smtp.SendAsync(message, message); 
     } 
     catch (Exception) 
     { 
      if (mem != null) 
      { 
       mem.Dispose(); 
       mem.Close(); 
      } 
      throw; 
     } 
    } 

    private void SmtpSendCompleted(object sender, AsyncCompletedEventArgs e) 
    { 
     var message = e.UserState as MailMessage; 
     if (message != null) 
     { 
      foreach (var attachment in message.Attachments) 
      { 
       if (attachment != null) 
       { 
        attachment.Dispose(); 
       } 
      } 
      message.Dispose(); 
     } 
     if (e.Cancelled) 
      EmailSendCancelled?.Invoke(this, EventArgs.Empty); 
     else if (e.Error != null) 
     { 
      EmailSendFailure?.Invoke(this, EventArgs.Empty); 
      throw e.Error; 
     } 
     else 
      EmailSendSuccess?.Invoke(this, EventArgs.Empty); 
    } 
相关问题