feat(gmail): add sendBatch operation with throttling and dryRun flag#60
Conversation
- Wire sendBatch and sendFromTemplate into listTools for tool discovery - sendBatch implementation, types, SDK spec, and runtime were already present - All 3 sendBatch unit tests pass (multi-recipient, dryRun, error handling) Closes #51
📝 WalkthroughWalkthroughThis PR adds two new Gmail tool definitions to the hardcoded tool-discovery structure: Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~5 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📊 Type Coverage ReportType Coverage: 98.61% This PR's TypeScript type coverage analysis is complete. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gdrive-mcp | d02369d | Commit Preview URL Branch Preview URL |
Mar 28 2026, 08:12 PM |
🔒 Security Scan SummaryGenerated on: Sat Mar 28 20:12:33 UTC 2026 Scan Results
Summary
Recommendations
Security report generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d02369d2d5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }, | ||
| { | ||
| name: 'sendBatch', | ||
| signature: 'sendBatch({ subject: string, template: string, recipients: Array<{ to: string, variables: Record<string, string>, cc?: string[], bcc?: string[] }>, delayMs?: number, isHtml?: boolean, dryRun?: boolean, from?: string })', |
There was a problem hiding this comment.
Remove unsupported per-recipient cc/bcc from sendBatch docs
The new sendBatch signature in tool discovery advertises recipients[].cc/recipients[].bcc, but the actual operation only supports { to, variables } per recipient (BatchRecipient) and sendBatch() only reads recipient.to and recipient.variables before calling sendMessage. In practice, callers that rely on gdrive://tools will provide per-recipient CC/BCC and silently get incorrect behavior (those recipients are never included), which makes this discovery metadata inaccurate and misleading.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/tools/listTools.ts`:
- Line 260: The sendBatch signature advertises per-recipient cc/bcc but the
runtime path that builds sendOpts (in the code that constructs sendOpts for each
recipient within the Gmail send flow) does not forward
recipient.cc/recipient.bcc, causing loss of those fields; update the code that
constructs sendOpts (the routine preparing per-recipient send options used by
sendEmail/send or the Gmail transporter) to copy recipient.cc and recipient.bcc
(when present) into sendOpts.cc and sendOpts.bcc (preserving existing global
from/delivery options and merging arrays appropriately), and ensure downstream
send logic accepts those properties so the advertised contract for sendBatch
(recipients with cc?: string[], bcc?: string[]) is honored.
- Around line 261-262: The docs and example claim a default delay of 5000ms but
Issue `#51/AC-2` requires 500ms; update the default throttling everywhere to
500ms: change the description string and the example in listTools.ts (the
description/examplar lines referencing gmail.sendBatch) to state 500ms, and
change the implementation default for the sendBatch function/method
(gmail.sendBatch / sendBatch) so its delayMs default parameter or fallback value
is 500 instead of 5000; also update any related tests or comments that reference
5000ms to 500ms to keep all surfaces consistent.
- Around line 252-263: The current tool list exposes two separate actions
sendFromTemplate and sendBatch; change this to a single operation-based tool
entry (e.g., a unified tool with an operation parameter) so callers pass
operation: "sendFromTemplate" | "sendBatch" and a single payload object; update
the signature/description to accept operation plus a union-typed payload (for
sendFromTemplate: { to: string[], subject: string, template: string, variables:
Record<string,string>, cc?: string[], bcc?: string[], isHtml?: boolean, from?:
string } and for sendBatch: { subject: string, template: string, recipients:
Array<{ to: string, variables: Record<string,string>, cc?: string[], bcc?:
string[] }>, delayMs?: number, isHtml?: boolean, dryRun?: boolean, from?: string
}) and adjust example and description to document both operations and return
shapes (messageId/threadId for sendFromTemplate, { sent, failed, results?,
previews? } for sendBatch); locate and modify the entries named sendFromTemplate
and sendBatch in src/tools/listTools.ts to a single operation-based entry and
ensure consumers are informed to switch to operation-based calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a6df1db7-f695-46b2-9648-b9b9b5bbc592
📒 Files selected for processing (1)
src/tools/listTools.ts
| { | ||
| name: 'sendFromTemplate', | ||
| signature: 'sendFromTemplate({ to: string[], subject: string, template: string, variables: Record<string, string>, cc?: string[], bcc?: string[], isHtml?: boolean, from?: string })', | ||
| description: 'Render a templated email ({{variable}} substitution in subject and body) and send it. Returns messageId and threadId.', | ||
| example: 'const result = await gmail.sendFromTemplate({ to: ["amy@example.com"], subject: "{{firstName}}, quick follow-up", template: "Hey {{firstName}},\\n\\n{{personalNote}}", variables: { firstName: "Amy", personalNote: "Great chat!" } });\nconsole.log(result.messageId);', | ||
| }, | ||
| { | ||
| name: 'sendBatch', | ||
| signature: 'sendBatch({ subject: string, template: string, recipients: Array<{ to: string, variables: Record<string, string>, cc?: string[], bcc?: string[] }>, delayMs?: number, isHtml?: boolean, dryRun?: boolean, from?: string })', | ||
| description: 'Send templated emails to multiple recipients with per-recipient variable substitution and configurable delay between sends (default 5000ms). Set dryRun: true to preview all rendered emails without sending. Returns { sent, failed, results?, previews? }.', | ||
| example: 'const result = await gmail.sendBatch({ subject: "Hi {{name}}", template: "Hello {{name}}, {{note}}", recipients: [{ to: "alice@example.com", variables: { name: "Alice", note: "checking in" } }, { to: "bob@example.com", variables: { name: "Bob", note: "quick update" } }], delayMs: 5000 });\nconsole.log(`Sent: ${result.sent}, Failed: ${result.failed}`);', | ||
| }, |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use the operation-based tool shape instead of adding action-specific entries.
Lines 252-263 add separate sendFromTemplate and sendBatch tools, which conflicts with the repository rule for src/**/*.ts. Please model this through a single operation-based entry (single operation parameter) to stay consistent with the rest of the contract surface.
As per coding guidelines, "src/**/*.ts: Use operation-based tool pattern with single operation parameter instead of separate tools per action".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/tools/listTools.ts` around lines 252 - 263, The current tool list exposes
two separate actions sendFromTemplate and sendBatch; change this to a single
operation-based tool entry (e.g., a unified tool with an operation parameter) so
callers pass operation: "sendFromTemplate" | "sendBatch" and a single payload
object; update the signature/description to accept operation plus a union-typed
payload (for sendFromTemplate: { to: string[], subject: string, template:
string, variables: Record<string,string>, cc?: string[], bcc?: string[],
isHtml?: boolean, from?: string } and for sendBatch: { subject: string,
template: string, recipients: Array<{ to: string, variables:
Record<string,string>, cc?: string[], bcc?: string[] }>, delayMs?: number,
isHtml?: boolean, dryRun?: boolean, from?: string }) and adjust example and
description to document both operations and return shapes (messageId/threadId
for sendFromTemplate, { sent, failed, results?, previews? } for sendBatch);
locate and modify the entries named sendFromTemplate and sendBatch in
src/tools/listTools.ts to a single operation-based entry and ensure consumers
are informed to switch to operation-based calls.
| }, | ||
| { | ||
| name: 'sendBatch', | ||
| signature: 'sendBatch({ subject: string, template: string, recipients: Array<{ to: string, variables: Record<string, string>, cc?: string[], bcc?: string[] }>, delayMs?: number, isHtml?: boolean, dryRun?: boolean, from?: string })', |
There was a problem hiding this comment.
sendBatch signature advertises per-recipient cc/bcc, but runtime does not pass them through.
Line 260 includes cc?: string[], bcc?: string[] on each recipient, but src/modules/gmail/send.ts (lines 125-185 snippet) constructs sendOpts without cc/bcc. This makes the discovery contract misleading and can cause silent data loss of requested recipients.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/tools/listTools.ts` at line 260, The sendBatch signature advertises
per-recipient cc/bcc but the runtime path that builds sendOpts (in the code that
constructs sendOpts for each recipient within the Gmail send flow) does not
forward recipient.cc/recipient.bcc, causing loss of those fields; update the
code that constructs sendOpts (the routine preparing per-recipient send options
used by sendEmail/send or the Gmail transporter) to copy recipient.cc and
recipient.bcc (when present) into sendOpts.cc and sendOpts.bcc (preserving
existing global from/delivery options and merging arrays appropriately), and
ensure downstream send logic accepts those properties so the advertised contract
for sendBatch (recipients with cc?: string[], bcc?: string[]) is honored.
| description: 'Send templated emails to multiple recipients with per-recipient variable substitution and configurable delay between sends (default 5000ms). Set dryRun: true to preview all rendered emails without sending. Returns { sent, failed, results?, previews? }.', | ||
| example: 'const result = await gmail.sendBatch({ subject: "Hi {{name}}", template: "Hello {{name}}, {{note}}", recipients: [{ to: "alice@example.com", variables: { name: "Alice", note: "checking in" } }, { to: "bob@example.com", variables: { name: "Bob", note: "quick update" } }], delayMs: 5000 });\nconsole.log(`Sent: ${result.sent}, Failed: ${result.failed}`);', |
There was a problem hiding this comment.
Default throttling value conflicts with linked requirement.
Line 261 (and the example on Line 262) documents a default of 5000ms, while Issue #51 / AC-2 specify a default of 500ms. Please align the documented and implemented default to one value and keep all surfaces consistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/tools/listTools.ts` around lines 261 - 262, The docs and example claim a
default delay of 5000ms but Issue `#51/AC-2` requires 500ms; update the default
throttling everywhere to 500ms: change the description string and the example in
listTools.ts (the description/examplar lines referencing gmail.sendBatch) to
state 500ms, and change the implementation default for the sendBatch
function/method (gmail.sendBatch / sendBatch) so its delayMs default parameter
or fallback value is 500 instead of 5000; also update any related tests or
comments that reference 5000ms to 500ms to keep all surfaces consistent.
Performance Comparison ReportOperation Performance
Memory Usage
Summary
Performance report generated by Claude Code |
Summary
Wires
sendBatchandsendFromTemplateintolistTools.tsfor tool discovery. The core implementation (types, function, SDK spec, SDK runtime) was already present on main.Changes
sendFromTemplateentry tolistTools.tsgmail sectionsendBatchentry tolistTools.tsgmail sectionImplementation Details
sendBatch(insrc/modules/gmail/send.ts):delayMs(default 5000ms) throttlingdryRun: truereturns rendered previews without any Gmail API calls{ to, status, messageId?, threadId?, error? }per recipient{ sent, failed, results?, previews? }Tests
All 3 unit tests pass:
Full suite: 568 tests pass, 0 failures.
Acceptance Criteria
Closes #51
Resolves GDRIVE-18
Summary by CodeRabbit
New Features