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
Description
Email.__init__acceptsportandsslkeyword arguments, but the auto-discovery branches in_resolve(EmailFactories.from_env/EmailFactories.from_address) build a freshCredentialsinstance using values returned byresolve_imap_host, never consulting the caller-suppliedport/ssl. The kwargs become no-ops without any warning.Location
email_profile/email.pylines ~40-101 (__init__,_resolve)email_profile/core/credentials.pyline ~32 (EmailFactories.from_address)Current Behavior
The caller's
port=2143, ssl=Falseare discarded.Expected Behavior
Caller-supplied
portandsslshould override the values returned by auto-discovery. Or, if the design is intentional, raise a clearTypeErrorwhen both are provided.Suggested Fix
Forward overrides through the factory:
(Use sentinel objects rather than default-value comparison if you want to distinguish "user passed the default" from "user did not pass anything";
port/sslshould default toNonein__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
Credentialsmanually, defeating the high-level API.Priority
High