From 8d3f1824f5b43cde198d41b5f51ff3e6278d8f8e Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Thu, 24 Sep 2026 09:15:49 -0400 Subject: [PATCH 1/2] Map `IO::TimeoutError` to `Net::TimeoutError` Since Ruby 4.0, Ruby raises an `IO::TimeoutError` when the `open_timeout` is reached. The fix: Similar to `Net::HTTP` in ruby/net-http#263, map those errors to `Net::TimeoutError`. This case is simpler though because net-imap only supports Ruby 3.2, and `IO::TimeoutError` exists in 3.2: https://docs.ruby-lang.org/en/3.2/IO/TimeoutError.html --- lib/net/imap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 3bd776fc..a9965aec 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -3702,7 +3702,7 @@ def tcp_socket(host, port) s = Socket.tcp(host, port, :connect_timeout => open_timeout) s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true) s - rescue Errno::ETIMEDOUT + rescue Errno::ETIMEDOUT, IO::TimeoutError raise Net::OpenTimeout, "Timeout to open TCP connection to " + "#{host}:#{port} (exceeds #{open_timeout} seconds)" end From 525656da99277a8b2e67c0205eeb43fb465b365e Mon Sep 17 00:00:00 2001 From: nick evans Date: Sat, 26 Sep 2026 15:34:39 -0400 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=85=20Add=20test=20for=20Net::OpenTim?= =?UTF-8?q?eout=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/net/imap/test_imap.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb index 95d61c11..a35fbca7 100644 --- a/test/net/imap/test_imap.rb +++ b/test/net/imap/test_imap.rb @@ -62,6 +62,14 @@ class IMAPTest < Net::IMAP::TestCase end end + def test_open_timeout + host = ENV.fetch("TEST_OPEN_TIMEOUT_HOST", "10.255.255.1") + pend host if host.start_with? "skip" + assert_raise(Net::OpenTimeout) do + Net::IMAP.new(host, open_timeout: 0) + end + end + def test_unexpected_eof server = create_tcp_server port = server.addr[1]