簡體   English   中英

為什么只能調用一次SmtpClient.SendAsync?

[英]Why can SmtpClient.SendAsync only be called once?

我正在嘗試使用SmtpClient在.NET中編寫通知服務(用於完全合法的非垃圾郵件目的)。 最初我只是通過每個消息循環並發送它,但這很慢,我想提高速度。 所以,我切換到使用'SendAsync',但現在第二次調用時出現以下錯誤:

An asynchronous call is already in progress. 

我讀到這意味着MS癱瘓System.Net.Mail以防止群發郵件。 這個對嗎? 如果是這樣,有沒有更好的方法在.NET中執行此操作,並且仍然能夠記錄每封電子郵件的結果(這對我們的客戶來說很重要)。 如果沒有,為什么SendAsync只能被調用一次?

根據文件

調用SendAsync后,必須等待電子郵件傳輸完成后再嘗試使用Send或SendAsync發送另一封電子郵件。

因此,要同時發送多個郵件,您需要多個SmtpClient實例。

您可以使用以下內容:

ThreadPool.QueueUserWorkItem(state => client.Send(msg));

這應該允許您的消息排隊並在線程可用時發送。

顯然,這不是企圖阻止群發郵件。

原因是SmtpClient類不是線程安全的。 如果要同時發送多個電子郵件,則必須生成一些工作線程(在.NET Framework中有幾種方法可以執行此操作)並在每個線程中創建單獨的SmtpClient實例。

我認為你誤解了XXXAsync類的方法。 這些異步調用的目的是允許程序繼續運行,而不需要方法來完成處理並首先返回。 然后,您可以通過訂閱對象的XXXReceived事件來繼續處理結果。

要同時發送多個郵件,您可以考慮使用更多的Thread

您每個SMTP客戶端一次只能發送一個。 如果您希望進行多個發送呼叫,請創建多個SMTP客戶端。

HTH,

科爾比非洲

正如這里的其他人所注意到的,你一次只能發送一封電子郵件,但是發送第一封電子郵件后發送另一封電子郵件的方法是處理SmtpClient類的.SendCompleted事件,然后轉到下一封電子郵件,發送。

如果您想同時發送許多電子郵件,那么就像其他人所說的那樣,使用多個SmtpClient對象。

有理由重用SmtpClient ,它限制了與SMTP服務器的連接數。 我無法為報告構建的每個線程實例化一個新的類SmtpClient類,或者SMTP服務器將忽略太多的連接錯誤。 這是我在這里找不到答案時提​​出的解決方案。

我最終使用AutoResetEvent來保持所有內容同步。 這樣,我可以繼續在每個線程中調用SendAsync ,但是等待它處理電子郵件並使用SendComplete事件重置它,以便下一個可以繼續。

我設置了自動重置事件。

        AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

我的類實例化時設置了共享SMTP客戶端。

        _smtpServer = new SmtpClient(_mailServer);
        _smtpServer.Port = Convert.ToInt32(_mailPort);
        _smtpServer.UseDefaultCredentials = false;
        _smtpServer.Credentials = new System.Net.NetworkCredential(_mailUser, _mailPassword);
        _smtpServer.EnableSsl = true;
        _smtpServer.SendCompleted += SmtpServer_SendCompleted;

然后當我調用send async時,我等待事件清除,然后發送下一個事件。

        _autoResetEvent.WaitOne();
        _smtpServer.SendAsync(mail, mail);
        mailWaiting++;

我使用SMTPClient SendComplete事件重置AutoResetEvent,以便下一封電子郵件發送。

private static void SmtpServer_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            MailMessage thisMesage = (MailMessage) e.UserState;
            if (e.Error != null)
            {
                if (e.Error.InnerException != null)
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: "
                                 + e.Error.Message + e.Error.InnerException.Message);
                }

                else
                {
                    writeMessage("ERROR: Sending Mail: " + thisMesage.Subject + " Msg: " + e.Error.Message);
                }
            }
            else
            {
                writeMessage("Success:" + thisMesage.Subject + " sent.");
            }
        if (_messagesPerConnection > 20)
        {  /*Limit # of messages per connection, 
            After send then reset the SmtpClient before next thread release*/
            _smtpServer = new SmtpClient(_mailServer);
            _smtpServer.SendCompleted += SmtpServer_SendCompleted;
            _smtpServer.Port = Convert.ToInt32(_mailPort);
            _smtpServer.UseDefaultCredentials = false;
            _smtpServer.Credentials = new NetworkCredential(_mailUser, _mailPassword);
            _smtpServer.EnableSsl = true;
            _messagesPerConnection = 0;
        }
            _autoResetEvent.Set();//Here is the event reset
            mailWaiting--;
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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