2009-05-30 70 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命令在处理时发出,例如在使用块中使用。