Skip to content

Email() port/ssl kwargs silently ignored when auto-discovery is used #69

Description

@FernandoCelmer

Description

Email.__init__ accepts port and ssl keyword arguments, but the auto-discovery branches in _resolve (EmailFactories.from_env / EmailFactories.from_address) build a fresh Credentials instance using values returned by resolve_imap_host, never consulting the caller-supplied port/ssl. The kwargs become no-ops without any warning.

Location

  • email_profile/email.py lines ~40-101 (__init__, _resolve)
  • email_profile/core/credentials.py line ~32 (EmailFactories.from_address)

Current Behavior

def __init__(self, server=None, user=None, password=None, port=993, ssl=True, storage=None):
    connection = self._resolve(server, user, password, port, ssl)
    ...

@staticmethod
def _resolve(server, user, password, port, ssl) -> Credentials:
    if server is None and user is not None and "@" in user and password:
        return EmailFactories.from_address(user, password)   # port/ssl dropped
    ...
Email("u@gmail.com", "pw", port=2143, ssl=False)
# resolves to Credentials(server="imap.gmail.com", port=993, ssl=True)

The caller's port=2143, ssl=False are discarded.

Expected Behavior

Caller-supplied port and ssl should override the values returned by auto-discovery. Or, if the design is intentional, raise a clear TypeError when both are provided.

Suggested Fix

Forward overrides through the factory:

@classmethod
def from_address(cls, address, password, *, port=None, ssl=None) -> Credentials:
    host = resolve_imap_host(address)
    return Credentials(
        server=host.host,
        user=address,
        password=password,
        port=port if port is not None else host.port,
        ssl=ssl if ssl is not None else host.ssl,
    )
# email.py
def _resolve(server, user, password, port, ssl):
    port_override = port if port != 993 else None
    ssl_override  = ssl if ssl is not True else None
    ...
    return EmailFactories.from_address(
        user, password, port=port_override, ssl=ssl_override,
    )

(Use sentinel objects rather than default-value comparison if you want to distinguish "user passed the default" from "user did not pass anything"; port / ssl should default to None in __init__.)

Impact

Users connecting to providers with non-standard ports (Proton Bridge, corporate IMAP gateways, dev sandboxes) cannot override the discovered values via the documented kwargs. They must drop down to constructing Credentials manually, defeating the high-level API.

Priority

High

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghighHigh priority — incorrect behavior, performance, API breakage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions