|
26 | 26 | from mcp_email_server.log import logger |
27 | 27 |
|
28 | 28 |
|
| 29 | +async def _send_imap_id(imap: aioimaplib.IMAP4 | aioimaplib.IMAP4_SSL) -> None: |
| 30 | + """Send IMAP ID command with fallback for strict servers like 163.com. |
| 31 | +
|
| 32 | + aioimaplib's id() method sends ID command with spaces between parentheses |
| 33 | + and content (e.g., 'ID ( "name" "value" )'), which some strict IMAP servers |
| 34 | + like 163.com reject with 'BAD Parse command error'. |
| 35 | +
|
| 36 | + This function first tries the standard id() method, and if it fails, |
| 37 | + falls back to sending a raw command with correct format. |
| 38 | +
|
| 39 | + See: https://github.com/ai-zerolab/mcp-email-server/issues/85 |
| 40 | + """ |
| 41 | + try: |
| 42 | + response = await imap.id(name="mcp-email-server", version="1.0.0") |
| 43 | + if response.result != "OK": |
| 44 | + # Fallback for strict servers (e.g., 163.com) |
| 45 | + # Send raw command with correct parenthesis format |
| 46 | + await imap.protocol.execute( |
| 47 | + aioimaplib.Command( |
| 48 | + "ID", |
| 49 | + imap.protocol.new_tag(), |
| 50 | + '("name" "mcp-email-server" "version" "1.0.0")', |
| 51 | + ) |
| 52 | + ) |
| 53 | + except Exception as e: |
| 54 | + logger.warning(f"IMAP ID command failed: {e!s}") |
| 55 | + |
| 56 | + |
29 | 57 | class EmailClient: |
30 | 58 | def __init__(self, email_server: EmailServer, sender: str | None = None): |
31 | 59 | self.email_server = email_server |
@@ -202,10 +230,7 @@ async def get_emails_metadata_stream( # noqa: C901 |
202 | 230 |
|
203 | 231 | # Login and select inbox |
204 | 232 | await imap.login(self.email_server.user_name, self.email_server.password) |
205 | | - try: |
206 | | - await imap.id(name="mcp-email-server", version="1.0.0") |
207 | | - except Exception as e: |
208 | | - logger.warning(f"IMAP ID command failed: {e!s}") |
| 233 | + await _send_imap_id(imap) |
209 | 234 | await imap.select(mailbox) |
210 | 235 |
|
211 | 236 | search_criteria = self._build_search_criteria( |
@@ -366,10 +391,7 @@ async def get_email_body_by_id(self, email_id: str, mailbox: str = "INBOX") -> d |
366 | 391 |
|
367 | 392 | # Login and select inbox |
368 | 393 | await imap.login(self.email_server.user_name, self.email_server.password) |
369 | | - try: |
370 | | - await imap.id(name="mcp-email-server", version="1.0.0") |
371 | | - except Exception as e: |
372 | | - logger.warning(f"IMAP ID command failed: {e!s}") |
| 394 | + await _send_imap_id(imap) |
373 | 395 | await imap.select(mailbox) |
374 | 396 |
|
375 | 397 | # Fetch the specific email by UID |
@@ -411,10 +433,7 @@ async def download_attachment( |
411 | 433 | await imap.wait_hello_from_server() |
412 | 434 |
|
413 | 435 | await imap.login(self.email_server.user_name, self.email_server.password) |
414 | | - try: |
415 | | - await imap.id(name="mcp-email-server", version="1.0.0") |
416 | | - except Exception as e: |
417 | | - logger.warning(f"IMAP ID command failed: {e!s}") |
| 436 | + await _send_imap_id(imap) |
418 | 437 | await imap.select("INBOX") |
419 | 438 |
|
420 | 439 | data = await self._fetch_email_with_formats(imap, email_id) |
|
0 commit comments