SmtpClient.Send随机导致SmtpException 4.7.0超时等待客户端输入

时间:2014-07-25 12:56:48

标签: c# .net exception exchange-server smtpclient

我似乎无法找到导致此问题的原因。

有时我得到SmtpException" 4.7.0超时等待客户输入"使用的以下代码:

using System;
using System.Net.Mail;

namespace SendMail
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                string html = "<h1>TEST</h1>";

                using (MailMessage mail = new MailMessage("sender@domain.com", "receiver@domain.com"))
                {
                    mail.Subject = "Test";
                    mail.IsBodyHtml = true;
                    mail.Body = html;

                    using (SmtpClient client = new SmtpClient("<internal ip address>"))
                    {
                        client.UseDefaultCredentials = false;
                        client.Credentials = new System.Net.NetworkCredential("<user name>", "<password>");

                        client.DeliveryMethod = SmtpDeliveryMethod.Network;
                        client.Send(mail);
                    }
                }
            }
        }
    }
}

它通常在第二次尝试时崩溃(i == 1)。

我知道我应该创建一个SmtpClient实例并在循环中重用它,但为了演示的目的,为了尽可能接近实际代码,它必须是这样的。虽然上述内容与我的生产代码完全不同,但它确实存在同样的随机问题。我想如果我能解决这个代码的问题,那么我就知道如何处理我的实际的代码,因为它确实是一个编码问题。我怀疑一个模糊的服务器配置问题,但我对它可能出现的问题不以为然。

奇怪的是:尽管是超时问题,但异常会很快被抛出;没有延迟会暗示实际超时问题。

邮件服务器是在 SP2上运行的MS 。在app.config文件中没有指定其他SMTP设置。

我尝试将代码置于Do...While循环中,该循环尝试五次以在将线程暂停一秒后发回电子邮件。不幸的是,这并没有帮助:当它失败时,它也会在下次尝试时失败。

我也在每次调用Thread.Sleep(<delay>)之前尝试使用client.Send(message),但它没有产生任何差异。

我们的网络管理员坚持在网络上运行,没有任何问题(由于错误的MTU设置或类似的东西没有丢包)。他支持这一事实,因为只有我的代码似乎有问题(而且他是对的)并且它不仅发生在网络的一部分(也是正确的)。

防火墙也不太可能造成这种情况,因为我的应用发送的每封邮件都使用内部地址。

有人在这里有线索吗?非常感谢。

更新

我似乎每次使用默认凭据时都能重现问题:

using (SmtpClient client = new SmtpClient("<internal ip address>"))
{
    client.UseDefaultCredentials = true;

    client.DeliveryMethod = SmtpDeliveryMethod.Network;
    client.Send(mail);
}

更新2:

不。不是每一次。现在一切都有效了(直到下一次)。

我真的不能把手指放在上面。

更新3:

今天有趣的新发展:我尝试在MS Outlook中创建一个新帐户,其地址与我在Exchange中使用的地址相同。只是这一次,而不是将其添加为MS Exchange地址,我尝试将其设置为POP3 / SMTP帐户。以下是测试连接时发生的情况:

Error reproduced inside MS Outlook

它是法语但是看最后一行:这是我用我的代码得到的完全相同的错误信息。这清楚地表明我的问题不在我的代码范围内。

当然,这也意味着整个线程不应该在SO上。不过,我希望这个额外的测试可以帮助那些正在努力解决类似问题的开发人员。

6 个答案:

答案 0 :(得分:2)

这听起来像服务器或网络问题。例如,引用此serverfault帖子:https://serverfault.com/questions/344684/exchange-2007-email-error-451-4-7-0-timeout-waiting-for-client-input

如果您的计算机和交换服务器之间存在防火墙,则可能是防火墙问题。防火墙阻止IP地址之间的端口,电子邮件的位置无关紧要。防火墙是我编程存在的祸根,所以如果服务器之间有防火墙,请务必询问您的网络管理员,并让他检查它是否正常工作。

它也可能是服务器上的坏NIC(网卡)甚至是坏的电缆。是的,你的网络管理员说网络坚如磐石......但绝不信任网络管理员。 ;)

实际上,您的网卡,网络设置或以太网电缆也可能存在问题。

您是否尝试过从不同的计算机上运行它?

答案 1 :(得分:1)

如果关闭异步,您可以通过更改代码来触发,如下所示。您需要检查AggregateException以查看是否在任何正在执行的线程上发生了错误。

static void Main(string[] args)
{
    for (int i = 0; i < 100; i++)
    {
        string html = "<h1>TEST</h1>";
        Task.Factory.StartNew(() =>
        {
            using (MailMessage mail = new MailMessage("sender@domain.com", "receiver@domain.com"))
            {
                mail.Subject = "Test";
                mail.IsBodyHtml = true;
                mail.Body = html;

                using (SmtpClient client = new SmtpClient("<internal ip address>"))
                {
                    client.UseDefaultCredentials = false;
                    client.Credentials = new System.Net.NetworkCredential("<user name>", "<password>");

                    client.DeliveryMethod = SmtpDeliveryMethod.Network;
                    client.Send(mail);
                }
            }
        }).ContinueWith(aex => {
            if (aex.Exception != null)
            {
                //add some logic to deal with the exception
            }
        });
    }
}

答案 2 :(得分:1)

最好在循环之前定义SmtpClient,同样的问题发生在我身上,这解决了它。

using System;
using System.Net.Mail;

namespace SendMail
{
    class Program
    {
        SmtpClient client = new SmtpClient("<internal ip address>");

        static void Main(string[] args)
        {

            client.UseDefaultCredentials = false;
            client.Credentials = new System.Net.NetworkCredential("<user name>", "<password>");
            //client.EnableSsl = true;
            //client.Port = 25;    
            client.DeliveryMethod = SmtpDeliveryMethod.Network;

            for (int i = 0; i < 100; i++)
            {
                string html = "<h1>TEST</h1>";

                using (MailMessage mail = new MailMessage("sender@domain.com", "receiver@domain.com"))
                {
                    mail.Subject = "Test";
                    mail.IsBodyHtml = true;
                    mail.Body = html;

                    client.Send(mail);
                }
            }
        }
    }
}

答案 3 :(得分:1)

我对这个消息传递问题相当新。我目前一直在处理消息传递应用程序,偶尔会将此异常抛入系统。 到目前为止,我在互联网上找到的答案指出,这是电子邮件发件人身份验证中的错误。也许每日提交的限制和每小时发送限制可能会禁止SMTP服务器对电子邮件进行身份验证。例如,如果smtps.bol.com.br每小时限制为50封电子邮件,则必须有60分钟的间隔才能发送新批次的邮件。 我在这里做了我的测试,我没有确定的答案,但我相信这可能就是这样。如果他们找到了明确的解决方案,请不要忘记发帖。

答案 4 :(得分:0)

确保在所有情况下对象都调用.Dispose()。

我在每天发送5000多封电子邮件的高度活跃的生产系统上看到了此问题,但是该问题只会发生在大约5%的电子邮件中。发送电子邮件的代码是在.Net 4.0之前编写的,该版本将Dispose()调用引入了SmtpClient和MailMessage。我做了一个非常简单的更改,以确保两个对象都已处置,并且在5天内没有再次看到问题。

不调用Dispose()的同一代码可以在不太活跃的系统上运行,而不会出现任何问题。我的理论是,如果您未能调用Dispose(),则会发生某种累积资源泄漏,并且只会在高负载下导致此错误。

答案 5 :(得分:-1)

几年前我在Amazon Aws服务器上遇到了类似的错误。这似乎是我的安全公司&#34; AllCovered.com&#34;我必须对我的服务器IP地址执行例外以允许发送smtp电子邮件。

如果忘记将新服务器设置为异常,我确实会收到此错误。