【问题标题】:SmtpClient Timeout doesn't workSmtpClient 超时不起作用
【发布时间】:2012-05-15 02:22:15
【问题描述】:

我已经设置了 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);

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

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

【问题讨论】:

    标签: c# smtp timeout


    【解决方案1】:

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

    您问是否有人遇到过同样的问题 - 我刚刚在 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时,直到 l5s 后我才收到超时错误。

    如果无法建立连接,为什么 Smtp.Timeout 无效

    如果端口 25 上没有任何监听,或者主机不可访问,则至少要等到 20 秒后才会发生超时,此时 system.net.tcpclient 层会超时。这是在system.net.mail 层之下。来自excellent article describing the problem and solution:

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

    无法更改邮件的超时时间(这是有道理的,邮件服务器通常已启动),实际上无法更改system.net.socket 的连接,这真的很令人惊讶。但是您可以进行异步连接,然后可以判断您的主机是否已启动并且端口是否打开。来自this MSDN thread,尤其是this post,此代码有效:

    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.");
    }
    

    【讨论】:

    • 但是,如果您尝试的 ip 不在端口 25 上侦听,或者该 ip 可能没有被任何人使用,超时是否在您的计算机上起作用?
    • 我试图打开一个套接字,它对你伤心的方法没有任何作用,当我从 cmd ^C 套接字时,它给了我操作超时异常。
    • 当没有主机监听时:是的,我也得到了 20 秒的超时。那是在 TCP 层。扩展了我的答案以解决该问题。
    • 非常感谢,我建立了一个站点,每个人都可以将 smtp 服务器添加到他们的帐户并发送消息。 +1 请求会对性能产生影响,但优于 20s 延迟。我认为理想的解决方案是使用 TcpClient 类构建我自己的 SmtpClient。
    • 如果成功了怎么办,即如何通过这个socket发送msg?
    【解决方案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
        }
    }
    

    此解决方案的代价是您无法在任务中获取异常详细信息。等一下,但也许这值得?

    【讨论】:

      猜你喜欢
      • 2012-10-21
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      • 2018-12-27
      • 2011-02-21
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      相关资源
      最近更新 更多