9

我已经设置了 SmtpClient 类的 Timeout 属性,但它似乎不起作用,当我给它一个 1 毫秒的值时,执行代码时超时实际上是 15 秒。我从msdn获取的代码。

string to = "jane@contoso.com";
string from = "ben@contoso.com";
string subject = "Using the new SMTP client.";
string body = @"Using this new feature, you can send an e-mail message from an application very easily.";
MailMessage message = new MailMessage(from, to, subject, body);
SmtpClient client = new SmtpClient("1.2.3.4");
Console.WriteLine("Changing time out from {0} to 100.", client.Timeout);
client.Timeout = 1;
// Credentials are necessary if the server requires the client 
// to authenticate before it will send e-mail on the client's behalf.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
client.Send(message);

我尝试了单声道的实现,它也不起作用。

有没有人遇到过同样的问题?

4

2 回答 2

16

重现您的测试 - 它适用于我

你问是否有人遇到过同样的问题——我刚刚在 Windows 7、VS 2008 和 .NET 2.0 上尝试了你的代码——它工作得很好。将超时设置为1,正如您所拥有的那样,我几乎立即收到此错误:

Unhandled Exception: System.Net.Mail.SmtpException: The operation has timed out
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at mailtimeout.Program.Main(String[] args) in c:\test\mailtimeout\Program.cs:line 29

我认为问题可能是您期望与超时不同的东西。超时意味着连接成功,但服务器没有返回响应。这意味着您实际上需要有一个服务器在您的目的地的端口 25 上进行侦听,但它没有响应。对于这个测试,我使用Tcl在 25 上创建一个没有做任何事情的套接字:

c:\> tclsh
% socket -server foo 25

当我将超时更改为 时15000,直到 l5 秒后我才收到超时错误。

如果无法建立连接,为什么 Smtp.Timeout 不起作用

如果端口 25 上没有任何东西在侦听,或者主机不可访问,则超时至少要等到 20 秒后才会发生,此时system.net.tcpclient层会超时。这是system.net.mail图层下方。来自描述问题和解决方案的优秀文章

您会注意到 System.Net.Sockets.TcpClient 和 System.Net.Sockets.Socket 这两个类都没有连接套接字的超时时间。我的意思是你可以设置一个超时。.NET 套接字在建立同步/异步套接字连接时调用 Connect/BeginConnect 方法时不提供连接超时。相反,如果连接尝试连接的服务器未在侦听或存在任何网络错误,则连接被迫等待很长时间,然后引发异常。默认超时为 20-30 秒

无法从 mail 更改超时(这是有道理的,邮件服务器通常已启动),实际上无法更改 connect from system.net.socket,这确实令人惊讶。但是您可以进行异步连接,然后可以判断您的主机是否已启动并且端口是否打开。从这个 MSDN 线程,特别是这篇文章,这段代码有效:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = socket.BeginConnect("192.168.1.180", 25, null, null);
// Two second timeout
bool success = result.AsyncWaitHandle.WaitOne(2000, true);
if (!success) {
    socket.Close();
    throw new ApplicationException("Failed to connect server.");
}
于 2012-05-06T04:38:18.587 回答
2

除了 ckhan 的回答,我想与您分享一个实现更短超时的建议:

var task = Task.Factory.StartNew(() => SendEmail(email));

if (!task.Wait(6000))
   // error handling for timeout on TCP layer (but you don't get the exception object)

然后在 SendEmail() 中:

using (var client = new SmtpClient(_serverCfg.Host, _serverCfg.Port)) 
{        
    try
    {
        client.Timeout = 5000;   // shorter timeout than the task.Wait()
        // ...
        client.Send(msg);
    }
    catch (Exception ex)
    {
        // exception handling
    }
}

此解决方案带有权衡,即您不会在任务中获得异常详细信息。等等,但也许这值得吗?

于 2015-04-08T16:20:41.107 回答