2008-11-11 200 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); 
    } 
相關問題