c# - mail - ¿Cuáles son las mejores prácticas para usar SmtpClient, SendAsync y Dispose en.NET 4.0?
smtpclient c# gmail (5)
En general, los objetos descartables deben eliminarse lo antes posible; la implementación de IDisposable en un objeto tiene la intención de comunicar el hecho de que la clase en cuestión contiene recursos costosos que deberían ser liberados determinísticamente. Sin embargo, si la creación de esos recursos es costosa y necesita construir muchos de estos objetos, puede ser mejor (en términos de rendimiento) mantener una instancia en la memoria y reutilizarla. Solo hay una forma de saber si eso hace alguna diferencia: ¡perfilarlo!
Re: desechando y Async: no puedes usar obviamente. En su lugar, normalmente dispone el objeto en el evento SendCompleted:
var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);
Estoy un poco perplejo sobre cómo administrar SmtpClient ahora que es desechable, especialmente si realizo llamadas usando SendAsync. Presumiblemente, no debería llamar a Dispose hasta que SendAsync se complete. Pero debería llamarlo alguna vez (por ejemplo, usando "usar"). El escenario es un servicio WCF que envía correos electrónicos periódicamente cuando se realizan llamadas. La mayor parte del cálculo es rápido, pero el envío de correo electrónico puede tomar un segundo más o menos, por lo que Async sería preferible.
¿Debo crear un nuevo SmtpClient cada vez que envío un correo? ¿Debo crear uno para toda la WCF? ¡Ayuda!
Actualización En caso de que haga una diferencia, cada correo electrónico siempre se personaliza para el usuario. El WCF está alojado en Azure y Gmail se utiliza como el anuncio publicitario.
La pregunta original fue solicitada para .NET 4, pero si ayuda a partir de .NET 4.5 SmtpClient implementa el método asincrónico SendMailAsync
.
Como resultado, enviar correo electrónico de forma asincrónica es el siguiente:
public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
using (var message = new MailMessage())
{
message.To.Add(toEmailAddress);
message.Subject = emailSubject;
message.Body = emailMessage;
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAsync(message);
}
}
}
Es mejor evitar el uso del método SendAsync.
Ok, vieja pregunta que sé. Pero me encontré con esto cuando necesitaba implementar algo similar. Solo quería compartir un código.
Estoy iterando sobre varios SmtpClients para enviar varios correos de forma asincrónica. Mi solución es similar a TheCodeKing, pero, en su lugar, estoy deshaciendo el objeto de devolución de llamada. También estoy pasando MailMessage como userToken para obtenerlo en el evento SendCompleted para que yo también pueda llamar a disponer de eso. Me gusta esto:
foreach (Customer customer in Customers)
{
SmtpClient smtpClient = new SmtpClient(); //SmtpClient configuration out of this scope
MailMessage message = new MailMessage(); //MailMessage configuration out of this scope
smtpClient.SendCompleted += (s, e) =>
{
SmtpClient callbackClient = s as SmtpClient;
MailMessage callbackMailMessage = e.UserState as MailMessage;
callbackClient.Dispose();
callbackMailMessage.Dispose();
};
smtpClient.SendAsync(message, message);
}
Puede ver por qué es especialmente importante deshacerse de SmtpClient con el siguiente comentario:
public class SmtpClient : IDisposable
// Summary:
// Sends a QUIT message to the SMTP server, gracefully ends the TCP connection,
// and releases all resources used by the current instance of the System.Net.Mail.SmtpClient
// class.
public void Dispose();
En mi caso, enviando varios correos usando Gmail sin deshacerme del cliente, solía obtener:
Mensaje: Servicio no disponible, cerrando el canal de transmisión. La respuesta del servidor fue: 4.7.0 Problema temporal del sistema. Inténtalo más tarde (WS). oo3sm17830090pdb.64 - gsmtp
Nota: .NET 4.5 SmtpClient implementa el método async awaitable
SendMailAsync
. Para versiones inferiores, use SendAsync
como se describe a continuación.
Siempre debe deshacerse de IDisposable
instancias IDisposable
en la primera oportunidad. En el caso de las llamadas asincrónicas, esto se realiza en la devolución de llamada después de enviar el mensaje.
var message = new MailMessage("from", "to", "subject", "body"))
var client = new SmtpClient("host");
client.SendCompleted += (s, e) => {
client.Dispose();
message.Dispose();
};
client.SendAsync(message, null);
Es un poco molesto que SendAsync
no acepte una devolución de llamada.