Отправить письмо при использовании SmtpClient - PullRequest
2 голосов
/ 14 февраля 2012

Я создал цикл отправки электронных писем, если они потерпели неудачу

Я прочитал, что не рекомендуется использовать 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));
}

Ответы [ 4 ]

3 голосов
/ 14 февраля 2012

Я хочу просто дополнить ответ Денниса.

Здесь упрощенная реализация оболочки 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 голос
/ 14 февраля 2012

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

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

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

0 голосов
/ 14 февраля 2012

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

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

0 голосов
/ 14 февраля 2012

Вы можете отправить письмо асинхронно, используя SmtpClient.SendAsync()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...