carrier/crates/mail-mcp/src
Kayos b681953824 Phase C: mail_mark, mail_attachment_get, mail_reply
Three new tools complete the planned Phase C scope:

- mail_mark { uid, action, folder? }: action is one of read, unread,
  flagged, unflagged, trash, archive. read/unread toggle \Seen via UID
  STORE +/-FLAGS.SILENT (idempotent, no fetch round-trip). flagged/
  unflagged the same for \Flagged. trash is a MOVE to Trash. archive
  errors out with a clear pointer to mail_move because Sulkta's Dovecot
  doesn't ship a canonical Archive folder.

- mail_attachment_get { uid, attachment_index, folder? }: fetches the
  full RFC822 (within the existing 20 MB raw_eml cap), parses with
  mail-parser, returns the N-th attachment as base64. The index matches
  mail_inbox_read's attachments[] ordering. Returns {filename,
  mime_type, size, content_base64}. SAFETY note in the tool description
  warns the LLM not to execute / render / open attachment bytes
  blindly.

- mail_reply { uid, body, body_html?, attachments?, reply_all?,
  to_override? }: fetches the original to pull From / Subject /
  Message-Id / References, then sends with proper In-Reply-To +
  References + 'Re: ' subject prefix (skipped if already prefixed).
  reply_all=true echoes the original Cc. to_override replaces To.
  Threading headers still set against the original regardless of
  to_override.

Smoke verified 2026-05-21:
- Send kayos->kayos with a 54-byte text attachment
- mail_inbox_read shows attachments=[('smoke.txt', 54)]
- mail_attachment_get returns the exact bytes (b'Hello from mail-mcp
  Phase C smoke!\r\nLine 2.\r\nLine 3.\r\n', 54 bytes)
- mail_mark unread -> flags=[] (\Seen cleared)
- mail_mark flagged -> flags=['\\Flagged']
- mail_reply -> message lands as 'Re: mail-mcp phase-C smoke' with
  In-Reply-To = parent Message-Id and References = parent Message-Id

ServerHandler instructions updated to enumerate all 10 tools + the new
attachment-safety note. Tools live on the wire: mail_send,
mail_inbox_list, mail_inbox_read, mail_folder_list, mail_search,
mail_thread, mail_move, mail_mark, mail_attachment_get, mail_reply.

Test count 27 -> 33: 2 for MarkAction::parse (alias coverage + unknown
rejection), 4 for tools::extract_addr (display-name strip + bare-addr
passthrough + garbage tolerance + ToField unwrap).
2026-05-21 08:42:39 -07:00
..
config.rs audit-fix round 3: LOW-1 mime cleanup, INFO-2 drop empty snippet, INFO-3 unit tests + format_imap_since tightening 2026-05-21 08:00:50 -07:00
imap.rs Phase C: mail_mark, mail_attachment_get, mail_reply 2026-05-21 08:42:39 -07:00
main.rs mail-mcp v0.1 — Rust MCP server for Sulkta email 2026-05-21 06:50:25 -07:00
smtp.rs smtp: extract validate_send_input + 9 unit tests for size caps 2026-05-21 08:23:18 -07:00
tools.rs Phase C: mail_mark, mail_attachment_get, mail_reply 2026-05-21 08:42:39 -07:00