Fix send-email schema; add template-based sending#82
Conversation
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (7)
📝 WalkthroughWalkthroughThis PR adds template-based email sending support to both ChangesTemplate-Based Email Sending
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/tools/sendEmail/sendEmail.ts (1)
30-55: ⚡ Quick winExtract template-vs-inline validation into a shared helper to eliminate duplication.
Lines 30–55 here are duplicated almost verbatim in
src/tools/sandbox/sendSandboxEmail.ts(lines 38–63). Any future change to the rules (e.g., a new forbidden field or a different error message) needs to be made in two places, which is error-prone. Consider a small helper insrc/utils/mailtrapAddresses.ts(or a newsrc/utils/mailtrapTemplate.ts) such asvalidateTemplateOrInline({ template_uuid, template_variables, subject, text, html, category })returning a discriminated{ mode: "template" } | { mode: "inline"; subject: string }so callers also get a narrowedsubjectand avoid theas stringcast at line 79.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/tools/sendEmail/sendEmail.ts` around lines 30 - 55, The validation logic for template vs inline email is duplicated in sendEmail (the block checking template_uuid, subject, html/text, template_variables, category) and sendSandboxEmail; extract this into a shared helper (e.g., validateTemplateOrInline) that accepts { template_uuid, template_variables, subject, text, html, category } and returns a discriminated result like { mode: "template" } | { mode: "inline", subject: string } (so callers get a narrowed subject without casts); replace the duplicated blocks in sendEmail and sendSandboxEmail with calls to validateTemplateOrInline and use its return to drive subsequent logic and error messages.src/types/mailtrap.ts (1)
29-40: ⚖️ Poor tradeoffConsider discriminated union to enforce template vs. inline shapes at the type level.
The merged interface with all fields optional means TypeScript won't catch invalid combinations (e.g.,
template_uuid+subjecttogether, ortemplate_variableswithouttemplate_uuid) at compile time — enforcement is deferred entirely to runtime. Modeling the two shapes as a discriminated union would make illegal states unrepresentable and let the type-checker catch misuse.♻️ Suggested discriminated union approach
-export interface SendMailToolRequest { - from?: MailtrapAddressParam; - to?: MailtrapAddressParam | MailtrapAddressParam[]; - subject?: string; - text?: string; - html?: string; - cc?: MailtrapAddressParam[]; - bcc?: MailtrapAddressParam[]; - category?: string; - template_uuid?: string; - template_variables?: Record<string, TemplateVariableValue>; -} +interface SendMailBaseRequest { + from?: MailtrapAddressParam; + to?: MailtrapAddressParam | MailtrapAddressParam[]; + cc?: MailtrapAddressParam[]; + bcc?: MailtrapAddressParam[]; +} + +interface SendMailInlineRequest extends SendMailBaseRequest { + template_uuid?: never; + template_variables?: never; + subject?: string; + text?: string; + html?: string; + category?: string; +} + +interface SendMailTemplateRequest extends SendMailBaseRequest { + template_uuid: string; + template_variables?: Record<string, TemplateVariableValue>; + subject?: never; + text?: never; + html?: never; + category?: never; +} + +export type SendMailToolRequest = SendMailInlineRequest | SendMailTemplateRequest;The same pattern can be applied to
SendSandboxEmailRequest.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types/mailtrap.ts` around lines 29 - 40, Change SendMailToolRequest into a discriminated union that enforces "template" vs "inline" shapes: one variant must have template_uuid (and may include template_variables) and must exclude inline-only fields like subject/text/html, and the other variant must omit template_uuid/template_variables and require at least one of subject/text/html; do the same refactor for SendSandboxEmailRequest. Update the exported types so the discriminator is template_uuid (present vs absent) and ensure all callers compile against the new union to catch illegal combinations at compile time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/tools/sendEmail/schema.ts`:
- Around line 58-63: The schema description for template_variables contradicts
runtime behavior: update the description of template_variables in
src/tools/sendEmail/schema.ts to state that template_variables must be used
together with template_uuid (i.e., "'template_variables' is only allowed when
'template_uuid' is provided and will be rejected otherwise") to match the
handler logic that throws when template_variables is present without
template_uuid; make the identical wording change in the sandbox schema at
src/tools/sandbox/schemas/sendSandboxEmail.ts so both schemas match the
validation performed by the sendEmail handler and its sandbox counterpart.
---
Nitpick comments:
In `@src/tools/sendEmail/sendEmail.ts`:
- Around line 30-55: The validation logic for template vs inline email is
duplicated in sendEmail (the block checking template_uuid, subject, html/text,
template_variables, category) and sendSandboxEmail; extract this into a shared
helper (e.g., validateTemplateOrInline) that accepts { template_uuid,
template_variables, subject, text, html, category } and returns a discriminated
result like { mode: "template" } | { mode: "inline", subject: string } (so
callers get a narrowed subject without casts); replace the duplicated blocks in
sendEmail and sendSandboxEmail with calls to validateTemplateOrInline and use
its return to drive subsequent logic and error messages.
In `@src/types/mailtrap.ts`:
- Around line 29-40: Change SendMailToolRequest into a discriminated union that
enforces "template" vs "inline" shapes: one variant must have template_uuid (and
may include template_variables) and must exclude inline-only fields like
subject/text/html, and the other variant must omit
template_uuid/template_variables and require at least one of subject/text/html;
do the same refactor for SendSandboxEmailRequest. Update the exported types so
the discriminator is template_uuid (present vs absent) and ensure all callers
compile against the new union to catch illegal combinations at compile time.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 12aae77b-5d37-443f-aac5-af407ea40026
📒 Files selected for processing (9)
CHANGELOG.mdsrc/tools/sandbox/__tests__/sendSandboxEmail.test.tssrc/tools/sandbox/schemas/sendSandboxEmail.tssrc/tools/sandbox/sendSandboxEmail.tssrc/tools/sendEmail/__tests__/sendEmail.test.tssrc/tools/sendEmail/schema.tssrc/tools/sendEmail/sendEmail.tssrc/types/mailtrap.tssrc/utils/mailtrapAddresses.ts
Per the Mailtrap Send Email API, `category` is an optional tracking tag, and recipients are satisfied by any of `to`, `cc`, or `bcc` — not specifically `to`. The send-email and send-sandbox-email schemas over-declared both: `category` was listed as required, and `to` was the only allowed recipient channel. - send-email schema: drop `category` and `to` from `required`; clarify descriptions. - send-sandbox-email schema: drop `to` from `required`; clarify descriptions. (`category` was already optional here.) - Handlers: validate at runtime that the combined to/cc/bcc list contains at least one recipient. - `parseSandboxTo` no longer throws on empty input; the combined check in the handler is the single source of truth. - Tests: update the empty-`to` cases to assert the new error message; add cc-only and bcc-only happy-path tests.
Adds `template_uuid` (with optional `template_variables`) so the MCP tools can send via a Mailtrap email template instead of inline content. Per the Mailtrap API, when `template_uuid` is set the inline fields (`subject`, `text`, `html`, `category`) must be omitted; this is enforced at runtime in both handlers. `subject` is no longer in the schema's `required` array because it does not apply to template sends. Also guards against `template_variables` passed without `template_uuid`.
Summary
Two related changes to
send-emailandsend-sandbox-emailMCP tools, on top of the customer-reported schema bug. Tracked in MT-22001.80c5c77— fix: align input schema with REST API requirementscategoryandtoremoved from schemarequiredarrays in both tools.to/cc/bccmust contain a recipient (matches the API's actual rule).parseSandboxTono longer throws on empty input — combined check in handler is the single source of truth.eea569e— feat: template-based sendingtemplate_uuidandtemplate_variablesparameters onsend-emailandsend-sandbox-email.template_uuidis set,subject/text/html/categorymust be omitted — enforced at runtime with a clear error.template_variableswithouttemplate_uuid.subjectremoved from schemarequired(does not apply to template sends).Background
A customer reported that the schema was out of sync with the Mailtrap Send Email API:
categorywas marked required (it's an optional tracking tag).towas marked required (per API, at least one ofto/cc/bccis required).template_uuidat all — callers couldn't send via a Mailtrap template.Test plan
Automated:
npm test— 186 / 186 jest tests pass (+ 10 new tests for cc/bcc-only sends and template paths).npm run lint— eslint + tsc clean.Manual against Mailtrap (suggested for QA):
to, onlycc, onlybcc, all combined.category(no longer schema-required).template_uuidonly; withtemplate_variables; withcc/bcc.template_uuid+subject/text/html/category→ rejected with clear message.template_variableswithouttemplate_uuid→ rejected.Summary by CodeRabbit
New Features
tois optional; at least one recipient must exist acrossto,cc, orbcc.Documentation
Tests