Skip to content

gmail_imap

gmail_imap

Gmail IMAP connector — reads email via IMAP with app password.

Simpler alternative to the OAuth-based Gmail connector. Uses Python's built-in imaplib + email modules (no dependencies).

Setup: generate an app password at https://myaccount.google.com/apppasswords

Classes

GmailIMAPConnector

GmailIMAPConnector(email_address: str = '', app_password: str = '', credentials_path: str = '', *, imap_host: str = '', imap_port: int | None = None, imap_security: str = '', max_messages: Optional[int] = None)

Bases: BaseConnector

Gmail connector using IMAP + app password.

No OAuth needed — just an email address and app password.

Source code in src/openjarvis/connectors/gmail_imap.py
def __init__(
    self,
    email_address: str = "",
    app_password: str = "",
    credentials_path: str = "",
    *,
    imap_host: str = "",
    imap_port: int | None = None,
    imap_security: str = "",
    max_messages: Optional[int] = None,
) -> None:
    self._email = email_address
    self._password = app_password
    self._credentials_path = credentials_path or _DEFAULT_CREDENTIALS_PATH
    self._imap_host = imap_host or self._default_imap_host
    self._imap_port = imap_port
    self._imap_security = imap_security
    # None means "use the persisted validation marker". Direct credentials
    # are not considered connected until a real LOGIN + SELECT succeeds.
    self._credentials_validated: bool | None = None
    # ``None`` means "no cap" — the full inbox is indexed. A positive
    # value is still honored for tests that want a bounded scan.
    self._max_messages = max_messages
    self._items_synced = 0
    self._items_total = 0
Functions
connect_with_credentials
connect_with_credentials(email_address: str, app_password: str, *, imap_host: str = '', imap_port: int | None = None, imap_security: str = '') -> None

Validate LOGIN + INBOX access, then persist the connection.

Source code in src/openjarvis/connectors/gmail_imap.py
def connect_with_credentials(
    self,
    email_address: str,
    app_password: str,
    *,
    imap_host: str = "",
    imap_port: int | None = None,
    imap_security: str = "",
) -> None:
    """Validate LOGIN + INBOX access, then persist the connection."""
    email_address = email_address.strip()
    app_password = app_password.strip()
    if not email_address or not app_password:
        raise ValueError("Email address and app password are required")

    host = (imap_host or self._host_for_email(email_address)).strip()
    if not host:
        raise ValueError("An IMAP host is required")
    security = _normalize_imap_security(imap_security)
    port = _normalize_imap_port(imap_port, security)

    imap = self._open_authenticated_imap(
        email_address,
        app_password,
        host,
        port,
        security,
    )
    self._close_imap(imap)

    save_tokens(
        self._credentials_path,
        {
            "email": email_address,
            "password": app_password,
            "imap_host": host,
            "imap_port": port,
            "imap_security": security,
            "validated": True,
        },
    )
    self._email = email_address
    self._password = app_password
    self._imap_host = host
    self._imap_port = port
    self._imap_security = security
    self._credentials_validated = True

Functions