-
Notifications
You must be signed in to change notification settings - Fork 92
IMAP Login can run before server greeting (breaks email-oauth2-proxy / fast upstream setup) #218
Description
I haven't been able to get IMAP to work with https://github.com/simonrob/email-oauth2-proxy. Cursor with access to both codebases wrote this summary:
Summary
msgvault add-imap fails against a local plain-IMAP OAuth proxy (e.g. email-oauth2-proxy) with IMAP login: unexpected EOF, while Thunderbird succeeds with the same local host, port, and “no TLS to proxy” settings.
What I’m trying to do
- Run an OAuth 2.0 email proxy on the same machine that listens on plain IMAP on a high port (e.g. 1993).
- The proxy opens a separate TLS connection to the real provider (e.g. Office 365 IMAPS on 993), replaces
LOGINwithAUTHENTICATE XOAUTH2, etc. - Configure msgvault with
add-imap --no-tlsto that loopback host and port so traffic to the proxy is unencrypted, matching the proxy’s documented model. - Expectation: connection test succeeds like any other IMAP client (e.g. Thunderbird).
Actual behavior
msgvault add-imap ... --no-tlsreports:connection test failed: IMAP login: unexpected EOFwhen using a host name that reaches the proxy (e.g.localhost).
Environment (generic)
- OS: Windows 10.
- msgvault:
add-imapwith--no-tls, provider-agnostic mailbox. - Proxy: email-oauth2-proxy-style setup: local plain IMAP → remote
outlook.office365.com:993with TLS. (running near commit 779e70e5, need to update it) - Proxy config:
local_address = localhostfor the IMAP server section; remoteserver_address/server_portas required by the provider.
Evidence
1. msgvault does not wait for the IMAP greeting before Login
In internal/imap/client.go, after DialInsecure / DialTLS / DialStartTLS, the code calls Login(...).Wait() immediately with no WaitGreeting() (or equivalent).
2. go-imap v2 behavior
In github.com/emersion/go-imap/v2 (imapclient):
DialInsecurereturnsNew(conn, options)as soon as TCP is connected; it does not block until the server greeting is received.Login()sends theLOGINcommand viabeginCommandwithout an explicitWaitGreeting()first.
So the client may emit LOGIN on the wire before the server (here, the proxy) has finished bringing up the upstream session (TCP + TLS + provider greeting).
3. Proxy debug log (ordering)
With proxy --debug, a failing attempt showed (paraphrased):
- Inbound from msgvault: censored
T1 LOGIN … - Outbound toward provider:
T1 AUTHENTICATE XOAUTH2(+ payload) - Then server-side:
[ Client connected ]andStarting TLS handshake - Then
ConnectionAbortedError/ WinError 10053 during TLS handshake on the upstream connection, followed disconnect → client sees EOF during login.
That ordering is consistent with commands being driven to the upstream socket before its TLS handshake has completed, which can abort the connection on Windows (10053).
4. Why Thunderbird works but msgvault doesn’t
- Thunderbird (and typical GUI clients) follow the usual IMAP sequence: read the
* OKgreeting, then send commands likeLOGIN. That gives the proxy time to finish the outbound TLS session to the provider before authentication traffic is forwarded. - msgvault + go-imap v2 can send
LOGINimmediately after TCP connect, which does not guarantee the greeting has been processed or that the proxy’s upstream leg is ready, triggering the failure mode above.
This is an interoperability / spec-ordering issue: RFC 3501/9051 expect the client to wait for the greeting before commands; the library allows sending LOGIN without an explicit wait in the high-level path msgvault uses.
Suggested fix (implementation hint)
After successful Dial* and before Login, call (*imapclient.Client).WaitGreeting() and return a clear error if it fails. That matches IMAP ordering and aligns behavior with Thunderbird.
Optional follow-up: document that loopback host choice (localhost vs 127.0.0.1) depends on how local_address is set on the proxy (separate from this root cause).
Severity / impact
- Medium for users relying on a local OAuth IMAP proxy (common for Microsoft/Google with legacy-style
LOGIN). - Low for direct TLS to normal IMAP servers where the greeting arrives and is processed before any visible issue (many servers tolerate minimal slack, or timing hides the race).