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
LOGIN with AUTHENTICATE XOAUTH2, etc.
- Configure msgvault with
add-imap --no-tls to 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-tls reports: connection test failed: IMAP login: unexpected EOF when using a host name that reaches the proxy (e.g. localhost).
Environment (generic)
- OS: Windows 10.
- msgvault:
add-imap with --no-tls, provider-agnostic mailbox.
- Proxy: email-oauth2-proxy-style setup: local plain IMAP → remote
outlook.office365.com:993 with TLS. (running near commit 779e70e5, need to update it)
- Proxy config:
local_address = localhost for the IMAP server section; remote server_address / server_port as 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):
DialInsecure returns New(conn, options) as soon as TCP is connected; it does not block until the server greeting is received.
Login() sends the LOGIN command via beginCommand without an explicit WaitGreeting() 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 ] and Starting 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
* OK greeting, then send commands like LOGIN. 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
LOGIN immediately 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).
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-imapfails against a local plain-IMAP OAuth proxy (e.g. email-oauth2-proxy) withIMAP login: unexpected EOF, while Thunderbird succeeds with the same local host, port, and “no TLS to proxy” settings.What I’m trying to do
LOGINwithAUTHENTICATE XOAUTH2, etc.add-imap --no-tlsto that loopback host and port so traffic to the proxy is unencrypted, matching the proxy’s documented model.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)
add-imapwith--no-tls, provider-agnostic mailbox.outlook.office365.com:993with TLS. (running near commit 779e70e5, need to update it)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
LoginIn
internal/imap/client.go, afterDialInsecure/DialTLS/DialStartTLS, the code callsLogin(...).Wait()immediately with noWaitGreeting()(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
LOGINon 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):T1 LOGIN …T1 AUTHENTICATE XOAUTH2(+ payload)[ Client connected ]andStarting TLS handshakeConnectionAbortedError/ 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
* OKgreeting, then send commands likeLOGIN. That gives the proxy time to finish the outbound TLS session to the provider before authentication traffic is forwarded.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
LOGINwithout an explicit wait in the high-level path msgvault uses.Suggested fix (implementation hint)
After successful
Dial*and beforeLogin, 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 (
localhostvs127.0.0.1) depends on howlocal_addressis set on the proxy (separate from this root cause).Severity / impact
LOGIN).