簡體   English   中英

使用SmtpClient時發送電子郵件

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM