.NET发送电子邮件的最佳方法(System.Net.Mail有问题)

时间:2009-05-30 18:07:31

标签: .net asp.net smtp smtpclient system.net.mail

这似乎很直接。我需要从一些ASP.NET应用程序发送电子邮件。我需要始终如一地做到这一点,没有奇怪的错误,并且没有CPU利用率。我不是在谈论大量的电子邮件,只是偶尔的电子邮件。

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使用率的网络主机上运行,​​您将禁用您的应用程序池。所以这并不像有些人所说的那样微不足道。

所以我的问题是该怎么办?我需要做的就是这么简单;但是,那些“太多连接打开”错误是不可接受的,也不是100%的CPU使用率。我不想购买第三方组件,不是因为我便宜,而是因为我购买了足够的组件和MSDN订阅,因为简单的SMTP功能需要花费100到300美元,这似乎很疯狂。

我读到将MaxIdleTime设置得更高可能有所帮助,但我对此持怀疑态度。我不想因为微软不想遵守SMTP规范而冒风险我的应用程序池被禁用。

编辑:我查看了quiksoft.com组件,但它不支持SMTP身份验证,费用为500美元。必须有一个解决这个问题的方法。

7 个答案:

答案 0 :(得分:29)

在.NET 4.0中,SmtpClient现在是一次性的。 SMTP QUIT命令在处理时发出,例如在使用块中使用时。

答案 1 :(得分:22)

我遇到了与所述设置相同的CPU利用率问题。我最终向微软开了一张票,以确定问题的原因。 CPU利用率问题在于ServicePoint类。在ServicePoint类的内部,有一个每隔(MaxIdleTime / 2)毫秒运行的计时器。看到问题?通过将MaxIdleTime值更改为2,CPU利用率将下降到正常水平。

答案 2 :(得分:2)

我一直使用Quiksoft的EasyMail .NET组件,没有任何问题。

产品主页:http://www.quiksoft.com/emdotnet/

如果您只需要发送电子邮件,他们也有免费版本的组件:

http://www.quiksoft.com/freesmtp/

答案 3 :(得分: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:from@address.com\n";
            strMail += "RCPT TO:" + recipient + "\n";
            strMail += "DATA\n";
            strMail += "Subject: mySubject\n";
            strMail += "To:" + recipient + "\n";
            strMail += "From: \"From Real Name\" <from@address.com>\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

    }

答案 4 :(得分:1)

到目前为止,我对System.Net.Mail没有任何具体问题,但您始终可以使用旧的System.Web.Mail API,它是CDOSYS的包装。

答案 5 :(得分:1)

我过去曾使用过Quicksoft并且没有任何抱怨。您可以尝试的另一件事是切换SMTP配置以使用拾取文件夹,而不是使用网络发送,这应该解决“它不发送退出”问题。

答案 6 :(得分:-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