fix(imap): fix mojibake in nested emails, empty headers, and date handling (#909)

* fix(imap): fix mojibake in nested emails, empty headers, and date handling

- Add line-by-line mojibake fix fallback for complex emails with mixed content
- Apply empty header cleanup globally to fix nested message/rfc822 parts
- Add locale-independent date formatting (format_imap_date, format_rfc2822_date)
- Fill missing Date header from created_at field
- Fix getSubPart for non-multipart messages
- Accept CREATE requests from clients (e.g. Gmail creating Drafts)
- Strip whitespace from IMAP password
- Use MIMEText instead of MIMEMultipart for sent mail generation
- Keep body in original CTE encoding for correct BODYSTRUCTURE
- Update CHANGELOG (zh/en)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: consolidate IMAP changelog entries into single line

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dream Hunter
2026-03-22 20:52:18 +08:00
committed by GitHub
parent 64d11799b3
commit 03965f3612
7 changed files with 143 additions and 37 deletions

View File

@@ -81,13 +81,18 @@ class Account(imap4.MemoryAccount):
"""Custom account that initializes mailbox UID index on select."""
def _emptyMailbox(self, name, id):
"""Ignore CREATE for unknown mailboxes instead of crashing."""
return None
"""Return a dummy mailbox for CREATE requests (e.g. Gmail creating Drafts)."""
_logger.debug("Accepting CREATE request for %s", name)
return SimpleMailbox(name, self._client)
def create(self, pathspec):
"""Silently ignore mailbox creation requests from clients."""
_logger.debug("Ignoring CREATE request for %s", pathspec)
return False
"""Accept CREATE silently without actually creating mailboxes."""
_logger.debug("Ignoring CREATE for %s", pathspec)
return True
def listMailboxes(self, ref, wildcard):
"""Only list INBOX and SENT, ignore client-created mailboxes."""
return [("INBOX", self.mailboxes["INBOX"]), ("SENT", self.mailboxes["SENT"])]
@defer.inlineCallbacks
def select(self, name, readwrite=1):
@@ -110,6 +115,7 @@ class SimpleRealm:
sent = SimpleMailbox("SENT", client)
account = Account(username)
account._client = client
account.mailboxes = {"INBOX": inbox, "SENT": sent}
account.subscriptions = ["INBOX", "SENT"]