Два способа отправки электронной почты через SmtpClient асинхронно, разные результаты
Здесь простая концепция. Это для сайта, который строится с использованием MVC 3 и Entity Framework 4. После регистрации пользователя на сайте на его электронный адрес отправляется электронное письмо. Я впервые реализовал это с помощью SmtpClient.Send () и это сработало отлично. Затем мне пришла в голову блестящая идея попробовать отправить письмо асинхронно. Я испытываю проблемы с двумя асинхронными подходами, которые я пробовал.
Первая реализация (из этого неотвеченного сообщения: https://stackoverflow.com/questions/7558582/how-to-dispose-using-smtpclient-send-and-asynccallback):
public bool Emailer(){
.
.
.
using (var smtpClient = new SmtpClient())
{
smtpClient.EnableSsl = true;
smtpClient.Host = "smtp.gmail.com";
smtpClient.Port = 587;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword");
var sd = new SendEmailDelegate(smtpClient.Send);
var cb = new AsyncCallback(SendEmailResponse);
sd.BeginInvoke(message, cb, sd);
return true;
}
}
private delegate void SendEmailDelegate(System.Net.Mail.MailMessage m);
private static void SendEmailResponse(IAsyncResult ar)
{
try
{
SendEmailDelegate sd = (SendEmailDelegate)(ar.AsyncState);
sd.EndInvoke(ar); // "cannot access a disposed object" errors here
}
catch (Exception e)
{
_logger.WarnException("Error on EndInvoke.", e);
}
}
Это работало половину времени. В другой половине я бы получил ошибку "не могу получить доступ к удаленному объекту" в обратном вызове.
Следующая реализация (от члена с солидной репутацией: каковы рекомендации по использованию SmtpClient, SendAsync и Dispose в .NET 4.0):
var smtpClient = new SmtpClient();
smtpClient.EnableSsl = true;
smtpClient.Host = "smtp.gmail.com";
smtpClient.Port = 587;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("myaddress@gmail.com", "mypassword");
smtpClient.SendCompleted += (s, e) =>
{
smtpClient.Dispose();
message.Dispose();
};
smtpClient.SendAsync(message, null);
С этой реализацией я не получаю никаких ошибок, но есть заметно более длительная задержка (~5 секунд) в режиме отладки, Когда smtpClient.SendAsync () выполняется, что заставляет меня думать, что он не отправляется асинхронно.
Вопросы:
1) что не так в первом методе, который вызывает ошибки" disposed object"?
2) есть ли у второй реализации проблема, из-за которой электронная почта не отправляется асинхронно? Является ли 5-секундная задержка бессмысленной?
Может быть также важно отметить, что, хотя сайт не будет нуждаться в поддержке отправляя большое количество электронных писем (только регистрация пользователей, подписка на рассылку и т. д.), Мы ожидаем большое количество пользователей в будущем, поэтому мое решение отправлять электронные письма асинхронно.
Спасибо.
3 ответа:
Ваш метод кулака не будет работать должным образом из-за блока USING. После завершения использования блока SmtpClient объект будет удален. Таким образом, вы не можете получить доступ к нему в обработчике событий.
Советы: 1-Не используйте "using block" Для объекта MailMessage, он размещает ваш объект перед отправкой почты
2-утилизируйте объекты MailMessage на SmtpClient.Событие SendCompleted:smtpClient.SendCompleted += (s, e) => { message.Dispose(); };
3-set SendCompletedEventHandler для smtpClient объекта
smtpClient.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
4-еще код:
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) { // Get the unique identifier for this asynchronous operation. String token = (string)e.UserState; if (e.Cancelled) { //write your code here } if (e.Error != null) { //write your code here } else //mail sent { //write your code here } mailSent = true; }
Ваша задержка в 5 секунд странна и предполагает, что есть проблема, требующая решения. Первая часть кода просто скрывает проблему, но не устраняет ее.
SmtpClient.SendAsync
является предпочтительным методом асинхронной отправки электронной почты, так как он использует методыSmtpClient
, специально разработанные для этой цели. Он также проще в реализации и, как было доказано, работает тысячи раз.
SmtpClient.SendAsync
на самом деле будет отправлять только асинхронно, если ваш метод доставки неSpecifiedPickupDirectory
илиPickupDirectoryFromIis
. В в этих случаях он запишет файл сообщения в папку pickup перед возвращением. Проверьте раздел вашего конфигурационного файла<smtp>
. Я предполагаю, что вы используете один из этих методов,и проблема заключается в папке pickup. Удалите старые файлы, которые у вас могут быть, и проверьте, не является ли проблема вашей антивирусной программой, которая, скорее всего, ищет вирусы в каждом новом файле. Проверьте, установлены ли атрибуты шифрования или сжатия. Может быть и что-то еще. Лучший способ проверить, является ли папка источником проблема заключается в ручном копировании файла электронной почты в него.