From c4a8ce16280433dc52e45f3b3c04267357fc82d4 Mon Sep 17 00:00:00 2001 From: mickey-mikey <149929346+mickey-mikey@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:52:42 +1100 Subject: [PATCH 1/2] fix: default charset=None in search/uid_search to avoid Yahoo IMAP rejection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yahoo's IMAP server does not advertise UTF8=ACCEPT or UTF8=ONLY in its CAPABILITY response and rejects CHARSET utf-8 in SEARCH commands with BAD [CLIENTBUG]. Per RFC 3501 ยง6.4.4, CHARSET is optional in SEARCH commands, so defaulting to None (omitting it) is more correct and compatible. Fixes #126 Co-Authored-By: Claude Opus 4.6 --- aioimaplib/aioimaplib.py | 6 +++--- tests/test_aioimaplib.py | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/aioimaplib/aioimaplib.py b/aioimaplib/aioimaplib.py index 1130ef5..216060e 100644 --- a/aioimaplib/aioimaplib.py +++ b/aioimaplib/aioimaplib.py @@ -525,7 +525,7 @@ def has_pending_idle_command(self) -> bool: def idle_done(self) -> None: self.send('DONE') - async def search(self, *criteria, charset: Optional[str] = 'utf-8', by_uid: bool = False) -> Response: + async def search(self, *criteria, charset: Optional[str] = None, by_uid: bool = False) -> Response: args = ('CHARSET', charset) + criteria if charset is not None else criteria prefix = 'UID' if by_uid else '' @@ -738,10 +738,10 @@ async def logout(self) -> Response: async def select(self, mailbox: str = 'INBOX') -> Response: return await asyncio.wait_for(self.protocol.select(mailbox), self.timeout) - async def search(self, *criteria: str, charset: Optional[str] = 'utf-8') -> Response: + async def search(self, *criteria: str, charset: Optional[str] = None) -> Response: return await asyncio.wait_for(self.protocol.search(*criteria, charset=charset), self.timeout) - async def uid_search(self, *criteria: str, charset: Optional[str] = 'utf-8') -> Response: + async def uid_search(self, *criteria: str, charset: Optional[str] = None) -> Response: return await asyncio.wait_for(self.protocol.search(*criteria, by_uid=True, charset=charset), self.timeout) async def uid(self, command: str, *criteria: str) -> Response: diff --git a/tests/test_aioimaplib.py b/tests/test_aioimaplib.py index a3adc99..d6adeab 100644 --- a/tests/test_aioimaplib.py +++ b/tests/test_aioimaplib.py @@ -339,6 +339,33 @@ async def test_search_two_messages(with_server): assert b'1 2' == data[0] +@pytest.mark.asyncio() +async def test_search_default_charset_is_none(with_server): + """Default charset should be None to avoid sending CHARSET which some servers reject.""" + with_server.receive(Mail.create(['user'])) + imap_client = await login_user_async('user', 'pass', select=True) + + # Default charset=None should work (no CHARSET sent) + result, data = await imap_client.search('ALL') + assert 'OK' == result + assert b'1' == data[0] + + # Explicit charset='utf-8' should still work + result, data = await imap_client.search('ALL', charset='utf-8') + assert 'OK' == result + assert b'1' == data[0] + + # uid_search default charset=None should work + result, data = await imap_client.uid_search('ALL') + assert 'OK' == result + assert b'1' == data[0] + + # uid_search explicit charset='utf-8' should still work + result, data = await imap_client.uid_search('ALL', charset='utf-8') + assert 'OK' == result + assert b'1' == data[0] + + @pytest.mark.asyncio() async def test_search_messages(with_server): """Increase compatibility with https://docs.python.org/3/library/imaplib.html#imap4-example.""" From 9a63e23e253a2eb3816256a52cb4dee2edae944d Mon Sep 17 00:00:00 2001 From: mickey-mikey <149929346+mickey-mikey@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:35:38 +1100 Subject: [PATCH 2/2] ci: pin Poetry to 1.8.5 for Python 3.9 compatibility Poetry 2.x dropped Python 3.9 support, breaking CI for all PRs. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a952126..625547a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -32,6 +32,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: 1.8.5 virtualenvs-create: true virtualenvs-in-project: true - name: Load cached venv