Summary
The Gmail service should support all standard email operations a human would perform. Currently missing: direct reply (threaded), forward, reply-all, add/download attachments, and trash/delete.
Problem
Right now sendMessage and createDraft accept inReplyTo but threading is unreliable (especially with mailing list / ConvertKit emails). There's no explicit reply operation that guarantees correct threading with In-Reply-To + References headers. Forwarding is completely absent.
Proposed Operations
Priority 1 — Core
| Operation |
Purpose |
Gmail API |
replyToMessage |
Reply to a specific message (auto-sets subject, threading headers, recipient) |
users.messages.send with proper In-Reply-To, References, threadId |
replyAllToMessage |
Reply-all (includes CC recipients from original) |
Same as above, auto-populates all recipients |
forwardMessage |
Forward a message to new recipients with original content quoted |
users.messages.send with forwarded body + attachments |
Priority 2 — Attachment Handling
| Operation |
Purpose |
Gmail API |
listAttachments |
List attachments on a message (name, size, mimeType) |
users.messages.attachments.get |
downloadAttachment |
Download an attachment by ID |
users.messages.attachments.get |
sendWithAttachments |
Send/draft with file attachments |
Multipart MIME message |
Priority 3 — Message Management
| Operation |
Purpose |
Gmail API |
trashMessage |
Move message to trash |
users.messages.trash |
untrashMessage |
Restore from trash |
users.messages.untrash |
deleteMessage |
Permanently delete (skip trash) |
users.messages.delete |
markAsRead |
Remove UNREAD label |
users.messages.modify (already possible via modifyLabels but a convenience alias) |
archiveMessage |
Remove INBOX label |
users.messages.modify (same — convenience alias) |
Threading Fix for replyToMessage
The key issue with current inReplyTo is that we pass the Gmail message ID instead of building proper MIME headers. A correct reply needs:
- Set
threadId to the original message's threadId
- Set
In-Reply-To header to the original message's Message-ID header value
- Set
References header to original's References + Message-ID
- Prefix subject with
Re: if not already present
- Auto-populate
To from the original sender
replyToMessage should handle all of this from just a messageId input.
Human-Parity Checklist
After this + #42 (draft management), Gmail operations should cover:
Acceptance Criteria
Summary
The Gmail service should support all standard email operations a human would perform. Currently missing: direct reply (threaded), forward, reply-all, add/download attachments, and trash/delete.
Problem
Right now
sendMessageandcreateDraftacceptinReplyTobut threading is unreliable (especially with mailing list / ConvertKit emails). There's no explicit reply operation that guarantees correct threading withIn-Reply-To+Referencesheaders. Forwarding is completely absent.Proposed Operations
Priority 1 — Core
replyToMessageusers.messages.sendwith properIn-Reply-To,References,threadIdreplyAllToMessageforwardMessageusers.messages.sendwith forwarded body + attachmentsPriority 2 — Attachment Handling
listAttachmentsusers.messages.attachments.getdownloadAttachmentusers.messages.attachments.getsendWithAttachmentsPriority 3 — Message Management
trashMessageusers.messages.trashuntrashMessageusers.messages.untrashdeleteMessageusers.messages.deletemarkAsReadusers.messages.modify(already possible viamodifyLabelsbut a convenience alias)archiveMessageusers.messages.modify(same — convenience alias)Threading Fix for
replyToMessageThe key issue with current
inReplyTois that we pass the Gmail message ID instead of building proper MIME headers. A correct reply needs:threadIdto the original message's threadIdIn-Reply-Toheader to the original message'sMessage-IDheader valueReferencesheader to original'sReferences+Message-IDRe:if not already presentTofrom the original senderreplyToMessageshould handle all of this from just amessageIdinput.Human-Parity Checklist
After this + #42 (draft management), Gmail operations should cover:
getMessage,searchMessages,listMessages)getThread,listThreads)sendMessage)createDraft)sendDraft)modifyLabels,listLabels)Acceptance Criteria
replyToMessage({ messageId, body })sends a correctly threaded replyreplyAllToMessage({ messageId, body })includes all original recipientsforwardMessage({ messageId, to, body? })forwards with quoted original