2009-05-30 68 views
18

這似乎很簡單。我需要從一些ASP.NET應用程序發送電子郵件。我需要始終如一地執行此操作,而不會出現奇怪的錯誤,並且CPU利用率無法通過屋頂。我不是在談論羣發電子郵件,只是偶爾發送電子郵件。.NET發送電子郵件的最佳方法(System.Net.Mail有問題)

System.Net.Mail 出現將被嚴重破壞。 SmtpClient不會發出Quit命令(這可能是因爲Microsoft(R)對以下規範不感興趣),因此連接處於打開狀態。因此,如果有人試圖在該連接之前發送電子郵件,最後會關閉,您可以從SMTP服務器獲取有關打開的連接太多的錯誤。這是Microsoft(R)對修復完全不感興趣的錯誤。在這裏看到:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=146711

此外,如果你看看周圍的一些建議使用此代碼來解決這個問題:

smtpClient.ServicePoint.MaxIdleTime = 1; 
smtpClient.ServicePoint.ConnectionLimit = 1; 

好吧,沒錯,它「解決」被留下的連接問題打開。但是,如果您喜歡,請一直在服務器上嘗試它,導致進程(在本例中爲w3wp.exe)運行的CPU跳轉並保持100%,直到應用程序池被回收爲止。無論出於何種原因,運行mscorwks.dll!CreateApplicationContext的線程都是罪魁禍首。

這具有非常好的副作用,如果您在持續100%CPU使用率的Web主機上運行,​​您將禁用應用程序池。所以這並不像有些人所建議的那樣微不足道。

所以我的問題是做什麼?我需要做的是如此簡單;然而,讓這些「連接打開太多」的錯誤是不可接受的,也不是100%的CPU使用率。我不想購買第三方組件,並不是因爲我便宜,但是我購買了足夠的組件和MSDN訂閱,看起來很瘋狂,爲了簡單的SMTP功能需要花費100- 300美元。

我讀到設置MaxIdleTime更高可以幫助,但我對此持懷疑態度。我不想冒我的應用程序池被禁用,因爲微軟不想遵循SMTP規範。

編輯:我看着quiksoft.com組件,但它不支持SMTP認證,它的成本爲500美元。必須有解決這個問題的辦法。

+0

根據您提供的鏈接,它顯示錯誤已被修復。有沒有可能你錯過了一個服務包? – overslacked 2009-05-30 19:45:56

+0

我看到它說「已解決」的地方。但是我沒有看到其他的音符。我已經將服務器更新到最新的SP以及所有這些。當我看到之前通常看起來MS只是意味着他們不會修復它。他們也有我在那裏列出的「解決方法」。這可能會更清楚。 – JustAProgrammer 2009-05-30 21:31:22

回答

22

我遇到了與上述設置相同的CPU利用率問題。我最終打開了與微軟的票據,以確定問題的原因。 CPU利用率問題在於ServicePoint類。在ServicePoint類的內部,有一個計時器每運行一次(MaxIdleTime/2)毫秒。看到問題了嗎?通過將MaxIdleTime值更改爲2,CPU利用率將下降到正常水平。

1

儘管到目前爲止我還沒有遇到任何與System.Net.Mail有關的問題,但您始終可以使用較舊的System.Web.Mail API,它是CDOSYS的包裝。

+0

只要沒有與System.Net.Mail的麻煩,你有沒有嘗試從你的一個頁面發送電子郵件,然後立即發送另一個頁面?您的服務器可能允許多個連接。我敢打賭,如果你運行TCPView,你的連接會長時間保持打開狀態。另外,System.Web.Mail不依賴於本地SMTP服務嗎?我需要通過已正確配置MX等的遠程主機發送電子郵件,以避免被標記爲垃圾郵件。 – JustAProgrammer 2009-05-30 19:40:41

+0

我沒有否認它有問題。我只是說我沒有遇到它。我沒有用太多(只是簡單的「聯繫我們」表格)。 System.Web.Mail不依賴本地SMTP服務器並支持使用遠程SMTP服務器。我已經廣泛使用了。這不是很優雅,但一直工作得很好。 – 2009-05-30 20:00:01

+0

哦,我不是在爭論,只是好奇。 :) – JustAProgrammer 2009-05-30 20:27:55

1

我用Quicksoft過去並沒有抱怨。你可以嘗試的另一件事是將SMTP配置切換到使用拾取文件夾,而不是使用應該避開「不發送QUIT」問題的網絡發送。

-1

我使用Sproc發送大部分郵件。我甚至可以附加一個文件。

 

CREATE PROCEDURE [dbo].[sendMail_With_CDOMessage] 
    @to VARCHAR(64), 
    @CC VARCHAR(1024)='', 
    @BCC VARCHAR(1024)='', 
    @subject VARCHAR(500)='', 
    @body VARCHAR(8000)='' , 
    @from VARCHAR(64), 
    @filename VARCHAR(255)='', 
    @priority INT = 0 
AS 
BEGIN 
    SET NOCOUNT ON 

    DECLARE 
     @handle INT, 
     @return INT, 
     @s VARCHAR(64), 
     @sc VARCHAR(1024), 
     @up CHAR(27), 
     @server VARCHAR(255) 

    SET @s = '"http://schemas.microsoft.com/cdo/configuration/' 

    SELECT 
     @s = 'Configuration.Fields(' + @s, 
     @up = 'Configuration.Fields.Update', 
     @server = 'smtp.yourdomain.com' 



    EXEC @return = sp_OACreate 'CDO.Message', @handle OUT 
    SET @sc = @s + 'sendusing").Value' 
    EXEC @return = sp_OASetProperty @handle, @sc, '2' 
    SET @sc = @s + 'smtpserver").Value' 
    EXEC @return = sp_OASetProperty @handle, @sc, @server 
    EXEC @return = sp_OAMethod @handle, @up, NULL 
    EXEC @return = sp_OASetProperty @handle, 'To', @to 
    EXEC @return = sp_OASetProperty @handle, 'CC', @CC 
    EXEC @return = sp_OASetProperty @handle, 'BCC', @BCC 
    EXEC @return = sp_OASetProperty @handle, 'From', @from 
    EXEC @return = sp_OASetProperty @handle, 'Subject', @subject 
    EXEC @return = sp_OASetProperty @handle, 'HTMLBody', @body  
    EXEC @return = sp_OASetProperty @handle, 'Priority', 'cdoHigh' 

    IF @filename IS NOT NULL 
     EXEC @return = sp_OAMethod @handle, 'AddAttachment', NULL, @filename 

    EXEC @return = sp_OAMethod @handle, 'Send', NULL 
    IF @return 0 
    BEGIN 
     PRINT 'Mail failed.' 
     IF @from IS NULL 
      PRINT 'From address undefined.' 
     ELSE 
      PRINT 'Check that server is valid.' 
    END 
    ELSE 
     PRINT 'Mail sent.' 

    EXEC @return = sp_OADestroy @handle 
END 

2

我們已經使用hMailserver獲得了巨大的成功。該配置可能需要一段時間才能習慣,但它是一款非常棒的免費郵件服務器產品。

如果您想自己推出自己的產品(多年前我曾與CDONTS共度時光),您可以從下面的代碼開始,根據您的內容定製。它使用TcpClient直接向郵件服務器創建TCP連接。當我有這麼多建立和調試的解決方案時,我並不推薦這樣做,但我發現這對於調試和確定預製MS郵件組件的問題來說非常有用。

private void Send_Email() 
    { 
     #region Email Sending Function 
     string strMail = ""; 

     try 
     { 
      // See RFC821 http://www.faqs.org/rfcs/rfc821.html for more specs 
      // TcpClient is an abstraction of a TCP Socket connection 
      TcpClient myTCP = new TcpClient(); 

      // Connect to the mail server's port 25 
      myTCP.Connect(mailserver, 25); 

      // Open a network stream which sends data to/from the TcpClient's socket 
      System.Net.Sockets.NetworkStream ns = myTCP.GetStream(); 

      // The data to send to the mail server, basically a raw SMTP mail message 
      strMail = "HELO\n"; 
      strMail += "MAIL FROM:[email protected]\n"; 
      strMail += "RCPT TO:" + recipient + "\n"; 
      strMail += "DATA\n"; 
      strMail += "Subject: mySubject\n"; 
      strMail += "To:" + recipient + "\n"; 
      strMail += "From: \"From Real Name\" <[email protected]>\n"; 
      strMail += "\n"; 
      strMail += " ---------------------------------------\n"; 
      strMail += "Name:  " + txtName.Text + "\n"; 
      strMail += "Address1: " + txtAddress1.Text + "\n"; 
      strMail += "Address2: " + txtAddress2.Text + "\n"; 
      strMail += "City:  " + txtCity.Text + "\n"; 
      strMail += "State: " + txtState.Text + "\n"; 
      strMail += "Zip:  " + txtZip.Text + "\n"; 
      strMail += "Email: " + txtEmail.Text + "\n"; 
      strMail += "Dealer: " + txtDealer.Text + "\n"; 
      strMail += " ---------------------------------------\n"; 
      strMail += "THIS IS AN AUTOMATED EMAIL SYSTEM. DO NOT REPLY TO THIS ADDRESS.\n"; 
      strMail += "\n.\n"; 

      // Defines encoding of string into Bytes (network stream needs 
      // an array of bytes to send -- can't send strings) 
      ASCIIEncoding AE = new ASCIIEncoding(); 
      byte[] ByteArray = AE.GetBytes(strMail); 

      // send the byte-encoded string to the networkstream -> mail server:25 
      ns.Write(ByteArray, 0, ByteArray.Length); 

      //ns.Read(ByteArray, 0, ByteArray.Length); 
      //lblStatus.Text = ByteArray.ToString(); 

      // close the network stream 
      ns.Close(); 

      // close the TCP connection 
      myTCP.Close(); 
     } 
     catch(Exception ex) 
     { 
      throw new Exception("Couldn't send email: <p>" + ex.Message); 
     } 

     #endregion 

    } 
27

在.NET 4.0中,SmtpClient現在是一次性的。 SMTP QUIT命令在處理時發出,例如在使用塊中使用。