Conversation
Both IMAP call sites (connect test + poll fetch) used raw imaplib.IMAP4_SSL, so a dual-stack host with unreachable IPv6 hangs until socket timeout. Add _IPv4IMAP4_SSL and _connect_imap() mirroring the existing _connect_smtp() pattern. Rebase after 5600105 moved gateway/platforms/email.py → plugins/platforms/email/adapter.py.
srojk34
force-pushed
the
fix/email-imap-ipv4-fallback
branch
from
June 22, 2026 14:14
0e54540 to
4c0c9f8
Compare
teknium1
reviewed
Jul 14, 2026
teknium1
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for covering both IMAP call sites and adding focused tests.
Problems
- The added fallback is reached only after
imaplib.IMAP4_SSL(...)raises (plugins/platforms/email/adapter.py:424in the PR diff).IMAP4_SSLusessocket.create_connection, which iterates resolved address candidates; when IPv6 times out but IPv4 then succeeds, the initial call returns successfully after the timeout, so this fallback is never invoked. The reported delay remains. - The new timeout test mocks an immediate constructor exception, so it does not exercise that dual-stack IPv6-timeout/IPv4-success sequence. Current main's SMTP helper has the same default-first retry shape at
plugins/platforms/email/adapter.py:542-549.
Suggested changes
- Use a strategy that can choose or race IPv4 before the default sequential connection path returns, while retaining IPv6-only support.
- Add a controlled dual-address regression test for the IPv6-timeout then IPv4-success case.
Automated hermes-sweeper review.
| address that is unreachable, the default connection hangs until socket | ||
| timeout. We retry through an IPv4-only socket path. TLS verification | ||
| errors are not retried. | ||
| """ |
Collaborator
There was a problem hiding this comment.
This fallback only runs after the default constructor raises. IMAP4_SSL uses socket.create_connection, which iterates resolved addresses; if IPv6 times out and a later IPv4 candidate succeeds, this call returns after the timeout rather than raising, so _IPv4IMAP4_SSL is never used. Please use a strategy that selects or races IPv4 before that default path can complete, and cover the IPv6-timeout/IPv4-success sequence.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
plugins/platforms/email/adapter.py(connect()and_fetch_new_messages()) used rawimaplib.IMAP4_SSL, which resolves via the system DNS and connects to whichever address comes first — often IPv6._connect_smtp()with_IPv4SMTP/_IPv4SMTP_SSLfallback classes, but IMAP had no equivalent.Fix
_IPv4IMAP4_SSL(mirrors_IPv4SMTP_SSL): overrides_create_socketto use_create_ipv4_connection.IMAP_CONNECT_TIMEOUTconstant (30 s) for consistency withSMTP_CONNECT_TIMEOUT._connect_imap()method: tries defaultIMAP4_SSLfirst; on connection-level failure retries with_IPv4IMAP4_SSL. TLS verification errors are not retried.imaplib.IMAP4_SSL(...)call sites withself._connect_imap().Validation
pytest tests/gateway/test_email.py -x -q→ 77 passedTest plan
test_default_connection_used_when_reachable— no IPv4 fallback when IMAP4_SSL connects normallytest_ipv6_timeout_falls_back_to_ipv4— timeout triggers IPv4-only retrytest_tls_verification_error_does_not_retry_ipv4— SSLError is re-raised, not retriedtest_connect_uses_connect_imap— connect() routes through _connect_imap()