[英]Send email when using SmtpClient
我创建了发送失败的电子邮件的循环
我读过,在代码中使用thread.sleep不是最佳实践,因为这可能会导致问题。 但是,有用于smtp客户端的客户端,该客户端在发送消息之前先处理事务。 我如何才能更好地将其用于Web应用程序?
using (var SmtpClient = new SmtpClient()) {
bool success = false;
int attemts = 0;
const int maxAttempts = 5;
do {
try {
SmtpClient.Send(mailMessage);
System.Threading.Thread.Sleep(400);
success = true;
} catch{
// ok wait for request
success = false;
attemts ++;
}
} while (success && (attemts == maxAttempts));
}
我想补充丹尼斯的答案。
这里是SmtpClient包装器的简化实现,它允许您将重试计数参数与SendAsync方法一起使用:
public class EmailSender {
private int _currentRetryCount;
private int _maxRetryCount;
private MailMessage _mailMessage;
private bool _isAlreadyRun;
public event SendEmailCompletedEventHandler SendEmailCompleted;
public void SendEmailAsync(MailMessage message, int retryCount) {
if (_isAlreadyRun) {
throw new InvalidOperationException(
"EmailSender doesn't support multiple concurrent invocations."
);
}
_isAlreadyRun = true;
_maxRetryCount = retryCount;
_mailMessage = message;
SmtpClient client = new SmtpClient();
client.SendCompleted += SmtpClientSendCompleted;
SendMessage(client);
}
private void SendMessage(SmtpClient client) {
try {
client.SendAsync(_mailMessage, Guid.NewGuid());
} catch (Exception exception) {
EndProcessing(client);
}
}
private void EndProcessing (SmtpClient client) {
if (_mailMessage != null) {
_mailMessage.Dispose();
}
if (client != null) {
client.SendCompleted -= SmtpClientSendCompleted;
client.Dispose();
}
OnSendCompleted(
new SendEmailCompletedEventArgs(null, false, null, _currentRetryCount)
);
_isAlreadyRun = false;
_currentRetryCount = 0;
}
private void SmtpClientSendCompleted(object sender, AsyncCompletedEventArgs e) {
var smtpClient = (SmtpClient)sender;
if(e.Error == null || _currentRetryCount >= _maxRetryCount) {
EndProcessing(smtpClient);
} else {
_currentRetryCount++;
SendMessage(smtpClient);
}
}
protected virtual void OnSendCompleted(SendEmailCompletedEventArgs args) {
var handler = SendEmailCompleted;
if (handler != null) {
handler(this, args);
}
}
}
public delegate void SendEmailCompletedEventHandler(
object sender, SendEmailCompletedEventArgs e);
public class SendEmailCompletedEventArgs : AsyncCompletedEventArgs {
public SendEmailCompletedEventArgs(
Exception error,
bool canceled,
object userState,
int retryCount)
: base(error, canceled, userState) {
RetryCount = retryCount;
}
public int RetryCount { get; set; }
}}
下面也是消费者代码示例:
var sender = new EmailSender();
sender.SendEmailCompleted += (o, eventArgs)
=> Console.WriteLine(eventArgs.RetryCount);
sender.SendEmailAsync(new MailMessage(), 5);
上面的代码片段中有很多简化,但是您应该了解主要思想。
我不确定您为什么需要此功能,但是我假设您要确保发送电子邮件。
以我的经验,最好让电子邮件服务器(或服务)处理电子邮件。 电子邮件服务器旨在重试传递,直到传递成功或永久失败。 如果您选择本地(例如IIS的内置电子邮件服务)或附近(例如您的ISP)的电子邮件服务器,则应该保证它始终可用。 配置SmtpClient
以在此处发送电子邮件。 由于服务器是关闭的,因此这应该不会失败,也不会花费很长时间,从而消除了在应用程序中重试的需要。
无论如何,我建议您实施日志记录以跟踪任何无法发送的电子邮件。
您可以使用SmtpClient.SendAsync()
异步发送邮件
将指定的电子邮件发送到SMTP服务器进行传递。 此方法不会阻塞调用线程,并允许调用方将对象传递给操作完成时要调用的方法。 -MSDN
这并不像您想的那么容易。 编写起来很容易,但是要使其真正起作用是很棘手的:)。 我建议您看看此SMTP发送器 。 我花了一些时间尝试编写自己的电子邮件发件人,但最终找到了这个工作库。 我遇到的问题之一就是使用GMail,此问题已在此处解决。 我没有与作者保持任何联系,但我强烈建议您这样做。
顺便说一句,是的,.Net似乎为您提供了所有内容,没有理由使用外部库,但是尝试几次后,请记住这篇文章并尝试一下。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.