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

发布于 2024-07-21 12:20:46 字数 1330 浏览 5 评论 0原文

这似乎很简单。 我需要从一些 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 使用率的 Web 主机上,您的应用程序池将会被禁用。 所以这并不像一些人认为的那么微不足道。

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

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

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

This seems to be pretty straight forward. I need to send email from some ASP.NET applications. I need to do this consistently without strange errors and without CPU utilization going through the roof. I'm not talking about mass emailing, just occasional emails.

System.Net.Mail appears to be horribly broken. The SmtpClient does not issue the Quit command (it may be because Microsoft(R) is not interested in following specifications), therefore a connection is left open. Therefore, if someone tries to email before that connection finally closes, you can get errors from the SMTP Server about too many connections open. This is a bug that Microsoft(R) is completely uninterested in fixing. See here:

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

Also, if you look around some suggest to use this code to solve this problem:

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

Ok, yes that does "solve" the problem of connections being left open. However, this consistently, try it on a server if you like, causes the CPU on which the process (in this case w3wp.exe) is running to jump and remain at 100% until your application pool is recycled. For whatever reason, the thread that runs mscorwks.dll!CreateApplicationContext is the culprit.

This has the very nice side effect that if you are running on a web host that frowns on sustained 100% CPU usage, you will get your application pool disabled. So this is not as trivial as some suggest.

So my question is what to do? What I need to do is so simple; however getting those "too many connections open" errors is not acceptable and nor is the 100% CPU usage. I don't want to purchase a third party component, not because I'm cheap, but I buy enough components and MSDN subscription that it seems crazy to have to shell out $100-$300 for simple SMTP functionality.

I read that setting the MaxIdleTime higher can help but I'm skeptical of that. I don't want to risk my app pool being disabled just because Microsoft doesn't want to follow the SMTP specification.

Edit: I looked at quiksoft.com components, however it does not support SMTP authentication and it costs $500. There's got to be a solution to this problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

留一抹残留的笑 2024-07-28 12:20:46

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

In .NET 4.0, SmtpClient is now disposable. The SMTP QUIT command is issued upon disposal such as when used in a using block.

花伊自在美 2024-07-28 12:20:46

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

I faced the same CPU utilization problem with the settings described. I ended up opening a ticket with Microsoft to determine the cause of the problem. The CPU utilization problem lies in the ServicePoint class. Internally in the ServicePoint class, there is a timer that runs every (MaxIdleTime/2) milliseconds. See the problem? By changing the MaxIdleTime value to 2, the CPU utilization will drop down to normal levels.

慕巷 2024-07-28 12:20:46

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

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

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

http://www.quiksoft.com/免费SMTP/

I've always used Quiksoft's EasyMail .NET components with no issues at all.

Product home page: http://www.quiksoft.com/emdotnet/

They also have a free version of the component if you only need to send out e-mails:

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

飘然心甜 2024-07-28 12:20:46

我们使用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

    }

We have used hMailserver with great success. The configuration can take a while to get used to but it has been a great -- and free -- mail server product.

If you want to roll your own (which I did years ago when I was having a bear of a time with CDONTS), you can start with the code below and customize to your heart's content. It uses the TcpClient to create a TCP connection directly to the mailserver. Not that I'd recommend this when there are so many established and debugged solutions, but I found this very useful for debugging and determining where the problem was with the prefab MS mail components.

    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

    }
空城缀染半城烟沙 2024-07-28 12:20:46

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

I've used Quicksoft in the past and have no complaints. Another thing you can try is switching the SMTP configuration to use a pickup folder instead of sending using the network which should get around the "it doesn't send QUIT" issue.

旧竹 2024-07-28 12:20:46

我使用 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  

I send most of my mail using a Sproc. I can even attach a file.

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  

少跟Wǒ拽 2024-07-28 12:20:46

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

While I haven't had any specific problems with System.Net.Mail so far, you can always use the older System.Web.Mail API which is a wrapper for CDOSYS.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文