hermes - 💡(How to fix) Fix Email adapter: _send_imap_id() breaks IMAP connection on servers without RFC 2971 support (e.g. Purelymail) [3 pull requests]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

The email gateway adapter fails to connect to IMAP servers that do not support RFC 2971 (IMAP ID extension), such as Purelymail. The error manifests as: ERROR gateway.platforms.email: [Email] IMAP connection failed: command: SELECT => Unknown command. In gateway/platforms/email.py, the _send_imap_id() function sends an ID command via imaplib.xatom("ID", ...) immediately after login. While the exception from a rejected ID command is caught, imaplib.xatom() internally registers the ID command in the Commands dict and sends raw bytes to the server. When the server responds with BAD Unknown command, the response desynchronizes imaplib's internal protocol parser. The subsequent imap.select("INBOX") call then fails because the parser is in an inconsistent state — producing the misleading command: SELECT => Unknown command error. 4. Observe error in logs

raise self.error('unknown extension command: %s' % name)

Root Cause

In gateway/platforms/email.py, the _send_imap_id() function sends an ID command via imaplib.xatom("ID", ...) immediately after login. While the exception from a rejected ID command is caught, imaplib.xatom() internally registers the ID command in the Commands dict and sends raw bytes to the server.

When the server responds with BAD Unknown command, the response desynchronizes imaplib's internal protocol parser. The subsequent imap.select("INBOX") call then fails because the parser is in an inconsistent state — producing the misleading command: SELECT => Unknown command error.

Fix Action

Fixed

Code Example

ERROR gateway.platforms.email: [Email] IMAP connection failed: command: SELECT => Unknown command.

---

imap.login(self._address, self._password)
_send_imap_id(imap)          # Sends ID, server responds BAD
imap.select("INBOX")         # Fails — parser desynchronized

---

EMAIL_ADDRESS=agent@example.com
   EMAIL_PASSWORD=***
   EMAIL_IMAP_HOST=imap.purelymail.com
   EMAIL_SMTP_HOST=smtp.purelymail.com

---

def _send_imap_id(imap: "imaplib.IMAP4") -> None:
    # Skip if server doesn't advertise ID capability
    if hasattr(imap, 'capabilities') and imap.capabilities:
        if b'ID' not in imap.capabilities:
            logger.debug("[Email] Server does not advertise ID capability, skipping.")
            return
    # ... rest of existing code

---

# if not name in self.capabilities:
#     raise self.error('unknown extension command: %s' % name)
RAW_BUFFERClick to expand / collapse

Bug Description

The email gateway adapter fails to connect to IMAP servers that do not support RFC 2971 (IMAP ID extension), such as Purelymail. The error manifests as:

ERROR gateway.platforms.email: [Email] IMAP connection failed: command: SELECT => Unknown command.

Root Cause

In gateway/platforms/email.py, the _send_imap_id() function sends an ID command via imaplib.xatom("ID", ...) immediately after login. While the exception from a rejected ID command is caught, imaplib.xatom() internally registers the ID command in the Commands dict and sends raw bytes to the server.

When the server responds with BAD Unknown command, the response desynchronizes imaplib's internal protocol parser. The subsequent imap.select("INBOX") call then fails because the parser is in an inconsistent state — producing the misleading command: SELECT => Unknown command error.

Call chain (in connect()):

imap.login(self._address, self._password)
_send_imap_id(imap)          # Sends ID, server responds BAD
imap.select("INBOX")         # Fails — parser desynchronized

The same issue occurs in _fetch_new_messages() which also calls _send_imap_id().

Steps to Reproduce

  1. Set up a Purelymail email account (any plan)
  2. Configure Hermes email gateway:
    EMAIL_ADDRESS=[email protected]
    EMAIL_PASSWORD=***
    EMAIL_IMAP_HOST=imap.purelymail.com
    EMAIL_SMTP_HOST=smtp.purelymail.com
  3. Start gateway: hermes gateway run
  4. Observe error in logs

Expected Behavior

The adapter should gracefully handle IMAP servers that don't support RFC 2971 by checking server capabilities before sending the ID command.

Suggested Fix

Add a capabilities check to _send_imap_id():

def _send_imap_id(imap: "imaplib.IMAP4") -> None:
    # Skip if server doesn't advertise ID capability
    if hasattr(imap, 'capabilities') and imap.capabilities:
        if b'ID' not in imap.capabilities:
            logger.debug("[Email] Server does not advertise ID capability, skipping.")
            return
    # ... rest of existing code

This mirrors the pattern already commented out in imaplib.xatom() source:

# if not name in self.capabilities:
#     raise self.error('unknown extension command: %s' % name)

Environment

  • Hermes Agent: current main
  • IMAP server: imap.purelymail.com (Purelymail)
  • Python imaplib

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING