2012-02-14 3 views
2

я создал цикл отправки электронной почты, если они неОтправить по электронной почте при использовании SmtpClient

Я прочитал, что это не лучшая практика, чтобы иметь Thread.sleep в коде, так как это может привести к проблемам. Однако используется для smtp-клиента, который удаляет транзакцию до отправки сообщения. Как я могу сделать это лучше, это будет использоваться в веб-приложении?

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

только что добавил результат async в контроллер и его почти идеальный – cpoDesign

ответ

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

В фрагменте кода есть много упрощений, но вы должны понимать основную идею.

0

Вы можете отправить почту асинхронно с помощью SmtpClient.SendAsync()

Посылает указанное сообщение электронной почты на сервер SMTP для доставки. Этот метод не блокирует вызывающий поток и позволяет вызывающему передать объект методу, который вызывается, когда операция завершается. - MSDN

1

Я не совсем уверен, зачем нужна эта функциональность, но я предполагаю, что вы хотите убедиться, что отправлено электронное письмо.

По моему опыту лучше всего разрешить почтовому серверу (или службе) обрабатывать электронную почту. Серверы электронной почты предназначены для повторной доставки до тех пор, пока не удастся или не удастся навсегда. Если вы выбрали сервер электронной почты, который является локальным (например, встроенная служба электронной почты IIS) или рядом с вашим интернет-провайдером, он должен в значительной степени гарантировать, что он всегда доступен. Настройте SmtpClient, чтобы отправить электронное письмо туда. Поскольку сервер находится рядом, это не должно терпеть неудачу и не займет много времени, устраняя необходимость повторных попыток в вашем приложении.

В любом случае, я бы порекомендовал вам внедрить ведение журнала для отслеживания любых сообщений электронной почты, которые не могли быть отправлены.

0

Это не так просто, как вы думаете. Его легко написать, но заставить его работать на самом деле сложно. Предлагаю вам взглянуть на это SMTP Sender. Я потратил некоторое время на то, чтобы написать своего собственного отправителя электронной почты, но в итоге нашел эту рабочую библиотеку. Одна из вещей, с которыми я столкнулась, - это работа с GMail, которая решается здесь. Я никак не связан с автором, но я очень рекомендую это.

btw - да, похоже, что .Net предоставляет все для вас, и нет причин использовать внешнюю библиотеку , но после того, как вы попробуете пару раз помните это сообщение и попробуйте.

+0

Ваша ссылка мертва ... – Dave