在.NET 4.0下使用SmtpClient,SendAsync和Dispose的最佳实践是什么

时间:2011-09-01 20:51:09

标签: c# .net-4.0 smtpclient

我对如何管理SmtpClient感到有些困惑,因为它是一次性的,特别是如果我使用SendAsync进行调用。据推测,在SendAsync完成之前,我不应该调用Dispose。但我应该打电话给它(例如,使用“使用”)。该方案是一个WCF服务,它在发出呼叫时定期发送电子邮件。大多数计算速度很快,但发送电子邮件可能需要一秒左右的时间,所以Async会更好。

每次发送邮件时都应该创建一个新的SmtpClient吗?我应该为整个WCF创建一个吗?救命啊!

更新如果它有所不同,则始终会为用户自定义每封电子邮件。 WCF托管在Azure上,Gmail用作邮件程序。

6 个答案:

答案 0 :(得分:157)

最初的问题是针对.NET 4提出的,但是如果它在.NET 4.5中有帮助,那么SmtpClient实现异步等待方法 SendMailAsync

因此,异步发送电子邮件如下:

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

最好避免使用SendAsync方法。

答案 1 :(得分:126)

注意:.NET 4.5 SmtpClient实现了async awaitable方法SendMailAsync。对于较低版本,请使用SendAsync,如下所述。


您应该尽早处置IDisposable个实例。在异步调用的情况下,这是在发送消息后的回调中。

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

SendAsync不接受回调,这有点烦人。

答案 2 :(得分:16)

一般而言,IDisisposable对象应尽快处理;在对象上实现IDisposable旨在传达这样一个事实,即所讨论的类拥有应该确定性释放的昂贵资源。但是,如果创建这些资源很昂贵并且您需要构建大量这些对象,那么将一个实例保留在内存中并重用它可能会更好(性能明智)。只有一种方法可以知道这是否有所不同:简介它!

Re:disposing和Async:显然你不能使用using。相反,您通常将对象放在SendCompleted事件中:

var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);

答案 3 :(得分:6)

好的,老问题我知道。但是当我需要实现类似的东西时,我偶然发现了这一点。我只是想分享一些代码。

我正在迭代几个SmtpClients以异步发送几个邮件。我的解决方案类似于TheCodeKing,但我正在处理回调对象。我也将MailMessage作为userToken传递给SendCompleted事件,所以我也可以调用dispose。像这样:

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

答案 4 :(得分:6)

您可以通过以下注释了解为什么处理SmtpClient特别重要:

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

在我使用Gmail发送多封邮件而不处理客户端的情况下,我曾经得到:

  

消息:服务不可用,关闭传输通道。该   服务器响应是:4.7.0临时系统问题。稍后再试   (WS)。 oo3sm17830090pdb.64 - gsmtp

答案 5 :(得分:0)

我在asp.net 5.0核心中使用了这种方式。

public async Task EmailSend(MessageModel messageModel)
    {
        using (MailMessage mailMessage = new MailMessage())
        {
            mailMessage.From = new MailAddress(_configuration.GetSection("EmailConfiguration").GetSection("FromEmail").Value.ToString(), _configuration.GetSection("EmailConfiguration").GetSection("FromName").Value.ToString(), Encoding.UTF8);
            mailMessage.Subject = messageModel.Subject;
            mailMessage.SubjectEncoding = Encoding.UTF8;
            mailMessage.Body = messageModel.Content;
            mailMessage.BodyEncoding = Encoding.UTF8;
            mailMessage.IsBodyHtml = true;
            mailMessage.BodyTransferEncoding = TransferEncoding.Base64;
            mailMessage.To.Add(new MailAddress(messageModel.To));
            NetworkCredential networkCredential = new NetworkCredential(_configuration.GetSection("EmailConfiguration").GetSection("Username").Value.ToString(), _configuration.GetSection("EmailConfiguration").GetSection("Password").Value.ToString());
            SmtpClient smtpClient = new SmtpClient();
            smtpClient.Host = _configuration.GetSection("EmailConfiguration").GetSection("SmtpServer").Value.ToString();
            smtpClient.EnableSsl = Convert.ToBoolean(_configuration.GetSection("EmailConfiguration").GetSection("SSL").Value);
            smtpClient.UseDefaultCredentials = Convert.ToBoolean(_configuration.GetSection("EmailConfiguration").GetSection("UseDefaultCredentials").Value);
            smtpClient.Port = Convert.ToInt32(_configuration.GetSection("EmailConfiguration").GetSection("Port").Value);
            smtpClient.Credentials = networkCredential;
            smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
            await smtpClient.SendMailAsync(mailMessage);
        }
    }