2008-11-11 6 views
30

J'utilise un composant de service via ASP.NET MVC. Je voudrais envoyer l'email de manière asynchrone pour laisser l'utilisateur faire d'autres choses sans avoir à attendre l'envoi.Comment envoyer un email avec des pièces jointes en utilisant SmtpClient.SendAsync?

Lorsque j'envoie un message sans pièce jointe, cela fonctionne correctement. Lorsque j'envoie un message avec au moins une pièce jointe en mémoire, cela échoue. Donc, je voudrais savoir s'il est possible d'utiliser une méthode asynchrone avec des pièces jointes en mémoire.

Voici la méthode d'envoi


    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); 
     } 
    } 

Voici mon erreur actuelle


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 --- 

Solution

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); 
    } 

Répondre

33

Ne pas utiliser "en utilisant" ici. Vous détruisez le flux de mémoire immédiatement après avoir appelé SendAsync, par ex. probablement avant que SMTP ne puisse le lire (puisqu'il est asynchrone). Détruisez votre flux dans le rappel.

0

J'ai essayé votre fonction et cela fonctionne même pour le courrier électronique avec des pièces jointes en mémoire. Mais voici quelques remarques:

  • Quel type de pièces jointes avez-vous essayé d'envoyer? EXE ?
  • L'expéditeur et le destinataire sont-ils tous les deux sur le même serveur de messagerie?
  • Vous devriez "attraper" l'exception et ne pas l'avaler simplement, que vous obtiendrez plus d'informations sur votre problème.
  • Que dit l'exception?

  • Est-ce que cela fonctionne si vous utilisez Send au lieu de SendAsync? Vous utilisez la clause 'using' et la fermeture de Stream avant l'envoi de l'email.

est ici bon texte sur ce sujet:

Sending Mail in .NET 2.0

+0

Je devrais mettre plus de code, désolé à ce sujet. Permettez-moi de modifier l'échantillon pour vous donner plus d'informations. – labilbe

+0

Est-il possible que les appels asynchrones s'exécutant sur le serveur VS Dev ne soient pas réellement appelés Async? Ma mémoire floue essaye de se rappeler quelque chose a dit quelque chose au sujet du serveur de serveur de VS de VS est le fil simple? –

+0

Le lien est mort maintenant. –

0

Une extension de la solution fournie dans la question d'origine nettoie également correctement les pièces jointes qui peuvent également nécessiter une élimination.

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); 
    } 
Questions connexes