claude.ai Zoho Mail MCP: binary email attachments (PDFs, images) are corrupted due to UTF-8 decoding

Resolved 💬 2 comments Opened May 25, 2026 by bemo-git Closed May 26, 2026

Environment

  • Claude Code (latest)
  • MCP: claude.ai remote Zoho Mail integration (mcp__claude_ai_Zoho_Mail_Reading_Search__*)
  • Tool: ZohoMail_getMessageAttachmentContent
  • Platform: macOS

Bug description

Calling ZohoMail_getMessageAttachmentContent on any binary attachment (PDF, image, Office doc) returns corrupted data. The binary content is being run through a UTF-8 decoder instead of being returned as base64. This makes it impossible to reconstruct the original file.

Reproduction

  1. Set up the claude.ai Zoho Mail MCP integration
  2. Find any email with a PDF attachment
  3. Call ZohoMail_getMessageAttachmentContent with the correct account/folder/message/attachment IDs
  4. Attempt to save the returned content to disk as a binary file

Expected behaviour

Binary attachment content should be returned as a base64-encoded string, allowing the caller to decode it to the original bytes.

Actual behaviour

Raw binary bytes are decoded as UTF-8 text:

  • Valid multi-byte UTF-8 sequences collapse N bytes into 1 character (reducing apparent content length)
  • Invalid UTF-8 byte sequences (extremely common in zlib/FlateDecode-compressed PDF streams) are silently replaced with U+FFFD (?)

Observed on a 31,581-byte QuickBooks-generated PDF:

  • Returned string length: 25,916 characters (not 31,581)
  • Characters with code point > 255: 11,418 (36% of content destroyed)
  • Code point 0xFFFD (replacement char) dominates the high-value characters

The resulting file is completely unreadable by any PDF viewer.

Suggested fix

In the MCP connector that calls the Zoho attachment content API endpoint, base64-encode the raw HTTP response body before serialising it into the JSON tool result. One line change. On the consumer side, the caller then base64-decodes to get the original bytes.

Impact

Every binary attachment retrieved through this MCP integration is silently corrupted. There is no fallback or error — the tool returns 200 OK with broken content. Users have no way to know the file is damaged until they try to open it.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗