背景
我编写了一个小型控制台应用程序,用于监视RabbitMQ队列中的电子邮件。每当一封电子邮件被推到队列中时,我的应用程序就会捡起这封电子邮件,处理并发送它。
码
下面是我的电子邮件服务的代码,它实际上是发送电子邮件。
public class MailService : IMailService
{
private readonly SmtpClient _smtpClient = new SmtpClient();
public void SendEmail(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
_smtpClient.SendAsync(emailMessage, null);
}
#region Helpers
private static MailMessage BuildEmailMessage(string toEmail, string subject, string body, bool isHtml)
{
const string fromEmailAddress = "james.brown@world.com";
var emailMessage = new MailMessage(fromEmailAddress, toEmail, subject, body) { IsBodyHtml = isHtml };
return emailMessage;
}
#endregion
}问题
我在RabbitMQ队列中有两封电子邮件,当我启动控制台应用程序用户时,它在发送第一封电子邮件后抛出以下异常(我在收件箱中收到了第一封电子邮件)。
异步调用已经在进行中。在调用此方法之前,必须完成或取消该方法。
我做了一些调查,并看到了this thread,这解释了为什么我得到这个。显然,使用SendAsync()并不是一条路,因为:
调用SendAsync后,必须等待电子邮件传输完成后,才能尝试使用send或SendAsync发送另一条电子邮件。
那么,这方面的推荐方法是什么呢?我可以为每封电子邮件创建一个新的SmtpClient类实例,但这真的是一个好主意吗?
发布于 2017-07-14 12:12:03
同步发送电子邮件,不需要使用SendAsync的旧异步语法。另外,确保您的SmtpClient一次只从一个线程中命中,方法是将它包装在using语句中。这是一个轻微的性能损失,但你可能不会注意到,除非你发送了大量的电子邮件。如果您要发送一个吨,那么重载您的MailService.SendEmail方法来接受一个IEnumerable<EmailModel>,并使用单个SmtpClient一次性发送它们。
public void SendEmail(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
using(var client = new SmtpClient())
{
_smtpClient.Send(emailMessage);
}
}
//this would be the right way to do async
public async Task SendEmailAsync(string toEmail, string subject, string body, bool isHtml)
{
var emailMessage = BuildEmailMessage(toEmail.Trim(), subject.Trim(), body, isHtml);
using(var client = new SmtpClient())
{
_smtpClient.SendMailAsync(emailMessage);
}
}
//this would be the right way to do multiple emails
//you'd need to create an EmailModel class to contain all the details for each email (similar to MailMessage, but it would prevent your own code from taking a dependency on System.Net.Mail
public void SendEmail(IEnumerable<EmailModel> emailModels)
{
var mailMessages = emailModels.Select(em => ConvertEmailModelToMailMessage(em));
using(var client = new SmtpClient())
{
foreach(var mailMessage in mailMessages)
{
//you may want some error handling on the below line depending on whether you want all emails to attempt to send even if one encounters an error
_smtpClient.Send(mailMessage);
}
}
}
private MailMessage ConvertEmailModelToMailMessage(EmailModel emailModel)
{
//do conversion here
}https://stackoverflow.com/questions/45083348
复制相似问题