Ответ 1
Не используйте здесь "использование". Вы уничтожаете поток памяти сразу после вызова SendAsync, например. вероятно, до того, как SMTP прочитает его (так как он асинхронно). Уничтожьте свой поток в обратном вызове.
Я использую компонент службы через ASP.NET MVC. Я хотел бы отправить электронное письмо асинхронным способом, чтобы позволить пользователю делать другие вещи, не дожидаясь отправки.
Когда я отправляю сообщение без вложений, он работает нормально. Когда я отправляю сообщение с хотя бы одним вложением в память, он терпит неудачу.
Итак, я хотел бы знать, можно ли использовать метод async с вложенными вложениями.
Вот метод отправки
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);
}
Не используйте здесь "использование". Вы уничтожаете поток памяти сразу после вызова SendAsync, например. вероятно, до того, как SMTP прочитает его (так как он асинхронно). Уничтожьте свой поток в обратном вызове.
Я пробовал вашу функцию, и она работает даже для электронной почты с вложениями в память. Но вот несколько замечаний:
Что говорит об исключении?
Работает ли он так, как вы используете Send вместо SendAsync? Вы используете предложение "using" и закрываете Stream до отправки электронной почты.
Вот хороший текст по этой теме:
Расширение для решения, поставленного в исходном вопросе, также правильно очищает вложения, которые также могут потребовать удаления.
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);
}