Как отправить электронное письмо с вложениями с помощью SmtpClient.SendAsync? - PullRequest
31 голосов
/ 11 ноября 2008

Я использую сервисный компонент через ASP.NET MVC. Я хотел бы отправить электронное письмо асинхронным способом, чтобы пользователь мог выполнять другие действия, не дожидаясь отправки.

Когда я отправляю сообщение без вложений, оно работает нормально. Когда я отправляю сообщение, содержащее хотя бы одно вложение в памяти, оно перестает работать.

Итак, я хотел бы знать, возможно ли использовать асинхронный метод с вложениями в памяти.

Вот способ отправки


    public static void Send() {

        MailMessage message = new MailMessage("from@foo.com", "too@foo.com");
        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("from@foo.com", "to@foo.com");
            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);
    }

Ответы [ 3 ]

34 голосов
/ 12 ноября 2008

Не используйте "использование" здесь. Вы уничтожаете поток памяти сразу после вызова SendAsync, например, вероятно, до того, как SMTP получит его прочитать (поскольку он асинхронный). Уничтожь свой поток в обратном вызове.

0 голосов
/ 10 декабря 2016

Расширение Решения, приведенное в исходном вопросе, также правильно очищает вложения, которые также могут потребовать удаления.

    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);
    }
0 голосов
/ 11 ноября 2008

Я попробовал вашу функцию, и она работает даже для электронной почты с вложениями в памяти. Но вот несколько замечаний:

  • Какой тип вложений вы пытались отправить? Exe?
  • Находятся ли отправитель и получатель на одном почтовом сервере?
  • Вы должны «поймать» исключение, а не просто проглотить его, чтобы получить больше информации о вашей проблеме.
  • Что говорит исключение?

  • Работает ли, когда вы используете Send вместо SendAsync? Вы используете предложение 'using' и закрываете Stream перед отправкой электронного письма.

Вот хороший текст по этой теме:

Отправка почты в .NET 2.0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...