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

.NET发送电子邮件的最佳方法(System.NET.Mail有问题),.net,asp.net,smtp,smtpclient,system.net.mail,.net,Asp.net,Smtp,Smtpclient,System.net.mail,这似乎很直截了当。我需要从一些ASP.NET应用程序发送电子邮件。我需要始终如一地做到这一点,而不会出现奇怪的错误,CPU利用率也不会急剧上升。我不是说群发邮件,只是偶尔发邮件 System.Net.Mail似乎严重损坏。SmtpClient不发出Quit命令(可能是因为Microsoft(R)对以下规范不感兴趣),因此连接保持打开状态。因此,如果有人试图在连接最终关闭之前发送电子邮件,您可能会从SMTP服务器收到关于打开的连接太多的错误。这是一个微软(R)完全没有兴趣修复的bug。请看这里:

这似乎很直截了当。我需要从一些ASP.NET应用程序发送电子邮件。我需要始终如一地做到这一点,而不会出现奇怪的错误,CPU利用率也不会急剧上升。我不是说群发邮件,只是偶尔发邮件

System.Net.Mail似乎严重损坏。SmtpClient不发出Quit命令(可能是因为Microsoft(R)对以下规范不感兴趣),因此连接保持打开状态。因此,如果有人试图在连接最终关闭之前发送电子邮件,您可能会从SMTP服务器收到关于打开的连接太多的错误。这是一个微软(R)完全没有兴趣修复的bug。请看这里:

此外,如果您环顾四周,建议使用此代码来解决此问题:

smtpClient.ServicePoint.MaxIdleTime = 1;
smtpClient.ServicePoint.ConnectionLimit = 1;
好的,是的,这确实“解决”了连接保持打开的问题。但是,如果愿意,可以在服务器上尝试,这会导致运行进程(在本例中为w3wp.exe)的CPU跳转并保持100%,直到应用程序池被回收。无论出于何种原因,运行mscorwks.dll的线程!CreateApplicationContext是罪魁祸首

这有一个非常好的副作用,即如果您运行的web主机不支持持续100%的CPU使用率,那么您的应用程序池将被禁用。因此,这并不像一些人所说的那么琐碎

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

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


编辑:我查看了quiksoft.com组件,但是它不支持SMTP身份验证,而且价格为500美元。这个问题一定有解决办法

虽然到目前为止,我在
System.Net.Mail
方面还没有遇到任何具体问题,但您始终可以使用旧的API,它是CDOSYS的包装器。

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

产品主页:

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


我过去使用过Quicksoft,没有任何抱怨。您可以尝试的另一件事是将SMTP配置切换为使用拾取文件夹,而不是使用网络发送,这样可以避免“it not send QUIT”问题

我使用存储过程发送大部分邮件。我甚至可以附加一个文件

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 创建过程[dbo]。[sendMail_With_CDOMessage] @至瓦查尔(64岁), @CC VARCHAR(1024)='', @BCC VARCHAR(1024)='', @受试者VARCHAR(500)='', @主体VARCHAR(8000)='', @来自瓦查尔(64), @文件名VARCHAR(255)='', @优先级INT=0 作为 开始 不计较 声明 @句柄INT, @返回INT, @s VARCHAR(64岁), @sc VARCHAR(1024), @上半部分(27), @服务器VARCHAR(255) 设置@s='”http://schemas.microsoft.com/cdo/configuration/' 挑选 @s='配置.Fields(+@s, @up='Configuration.Fields.Update', @服务器='smtp.yourdomain.com' EXEC@return=sp_OACreate'CDO.Message',@handle OUT 设置@sc=@s+'sendusing“.Value” EXEC@return=sp_OASetProperty@handle,@sc,'2' 设置@sc=@s+'smtpserver')。值' 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' 如果@filename不为NULL EXEC@return=sp_OAMethod@handle,'AddAttachment',NULL,@filename EXEC@return=sp_OAMethod@handle'Send',NULL 如果@return 0 开始 打印“邮件失败” 如果@from为空 打印“来自未定义的地址” 其他的 打印“检查服务器是否有效” 结束 其他的 打印“已发送邮件” EXEC@return=sp_OADestroy@handle 结束
我在所描述的设置中遇到了同样的CPU利用率问题。我最终向Microsoft打开了一个记录单以确定问题的原因。CPU利用率问题存在于ServicePoint类中。ServicePoint类内部有一个计时器,该计时器每(MaxIdleTime/2)运行一次毫秒。看到问题了吗?通过将MaxIdleTime值更改为2,CPU利用率将下降到正常水平。

我们已经非常成功地使用了该配置。该配置可能需要一段时间才能适应,但它是一款很棒的免费邮件服务器产品

如果你想玩你自己的(几年前我在CDONT玩得很开心的时候就是这么做的),您可以从下面的代码开始,并根据自己的内心内容进行自定义。它使用TcpClient直接创建到邮件服务器的TCP连接。当有这么多已建立和调试的解决方案时,我不建议这样做,但我发现这对于调试和确定预设MS mail com的问题所在非常有用成分

    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

    }
private void Send_Email()
{
#区域电子邮件发送功能
字符串strMail=“”;
尝试
{
//见RFC8