我创建了发送电子邮件的循环,如果它们失败
我已经读过在代码中使用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));
}
答案 0 :(得分:3)
我想补充丹尼斯的答案。
这里是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);
上面的代码片段有很多简化,但你应该理解主要的想法。
答案 1 :(得分:1)
我不确定您为何需要此功能,但我假设您要确保发送电子邮件。
根据我的经验,最好让电子邮件服务器(或服务)处理电子邮件。电子邮件服务器旨在重试传递,直到它成功或永久失败。如果您选择本地(如IIS的内置电子邮件服务)或附近(例如您的ISP)的电子邮件服务器,它应该几乎保证它始终可用。
配置SmtpClient
以在那里发送电子邮件。由于服务器已经关闭,因此不会失败并且不会花费很长时间,因此无需在应用程序中重试。
在任何情况下,我都建议您实施日志记录以跟踪无法发送的任何电子邮件。
答案 2 :(得分:0)
将指定的电子邮件发送到SMTP服务器以进行传递。此方法不会阻止调用线程,并允许调用者将对象传递给操作完成时调用的方法。 - MSDN
答案 3 :(得分:0)
这并不像你想象的那么容易。写它很容易,但让它实际工作是棘手的:)。 我建议你看一下这个SMTP Sender。我花了一些时间尝试编写自己的电子邮件发件人,但最终找到了这个工作库。我遇到的一个问题是使用GMail,这是在这里解决的。我没有以任何方式与作者联系,但我强烈推荐这一点。
顺便说一下 - 是的,似乎.Net为你提供了一切,没有理由使用外部 lib,但是在你尝试几次后记得这篇文章并尝试一下。