.net - mvc - ¿Cómo enviar un correo electrónico con archivos adjuntos utilizando SmtpClient.SendAsync?
send email mvc 5 (3)
Estoy usando un componente de servicio a través de ASP.NET MVC. Me gustaría enviar el correo electrónico de forma asíncrona para que el usuario pueda hacer otras cosas sin tener que esperar el envío.
Cuando envío un mensaje sin archivos adjuntos funciona bien. Cuando envío un mensaje con al menos un archivo adjunto en memoria, falla.
Entonces, me gustaría saber si es posible usar un método asíncrono con archivos adjuntos en memoria.
Aquí está el método de envío
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);
}
}
Aquí está mi error actual
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 ---
Solución
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);
}
He intentado tu función y funciona incluso para correo electrónico con archivos adjuntos de memoria. Pero aquí hay algunos comentarios:
- ¿Qué tipo de archivos adjuntos trataste de enviar? Exe ?
- ¿Ambos son remitente y receptor en el mismo servidor de correo electrónico?
- Debería "atrapar" la excepción y no solo tragarla, de lo que obtendrá más información sobre su problema.
¿Qué dice la excepción?
¿Funciona cuando usas Send en lugar de SendAsync? Está utilizando la cláusula ''using'' y cerrando Stream antes de que se envíe el correo electrónico.
Aquí hay un buen texto sobre este tema:
No use "usar" aquí. Estás destruyendo la secuencia de la memoria inmediatamente después de llamar a SendAsync, por ejemplo, probablemente antes de que SMTP lo lea (ya que es asíncrono). Destruye tu transmisión en la devolución de llamada.
Una extensión de la Solución proporcionada en la pregunta original también limpia correctamente los archivos adjuntos que también pueden requerir su eliminación.
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);
}