Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/tools/emails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -967,9 +967,9 @@ export function addEmailTools(
'send-batch-emails',
{
title: 'Send Batch Emails',
description: `**Purpose:** Send up to 100 transactional emails in one API call. Each item has the same fields as send-email (to, subject, text, from, etc.).
description: `**Purpose:** Send up to 100 transactional emails in one API call.

**NOT for:** Sending one email (use send-email) or the same content to a segment (use create-broadcast + send-broadcast).
**NOT for:** Sending one email (use send-email), scheduling emails, or sending the same content to a segment (use create-broadcast + send-broadcast). Batch emails support tags only as an extra per-email field.

**When to use:** User wants to send many individual emails in bulk (e.g. 50 password resets, 100 receipts). Not for one-to-many broadcasts.`,
inputSchema: {
Expand Down Expand Up @@ -1001,12 +1001,6 @@ export function addEmailTools(
.array(z.email())
.optional()
.describe('BCC email addresses'),
scheduledAt: z
.string()
.optional()
.describe(
"Optional schedule time. Uses natural language (e.g., 'tomorrow at 10am') or ISO 8601.",
),
tags: z
.array(
z.object({
Expand All @@ -1015,7 +1009,9 @@ export function addEmailTools(
}),
)
.optional()
.describe('Custom tags for tracking/analytics'),
.describe(
'Array of custom tags for tracking/analytics. Each tag has a name and value.',
),
topicId: z
.string()
.optional()
Expand Down Expand Up @@ -1056,7 +1052,6 @@ export function addEmailTools(
if (email.html) request.html = email.html;
if (email.cc) request.cc = email.cc;
if (email.bcc) request.bcc = email.bcc;
if (email.scheduledAt) request.scheduledAt = email.scheduledAt;
if (email.tags && email.tags.length > 0) request.tags = email.tags;
if (email.topicId) request.topicId = email.topicId;

Expand Down
38 changes: 38 additions & 0 deletions tests/tools/emails.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,41 @@ describe('send-batch-emails idempotency key', () => {
expect(batchSend).toHaveBeenCalledWith(expect.any(Array), undefined);
});
});

describe('send-batch-emails tags', () => {
beforeEach(() => {
vi.clearAllMocks();
batchSend.mockResolvedValue({
data: { data: [{ id: 'email_1' }] },
error: null,
});
});

it('passes tags to the SDK', async () => {
const client = await makeClient();
const result = await client.callTool({
name: 'send-batch-emails',
arguments: {
emails: [
{
from: 'onboarding@resend.dev',
to: ['foo@example.com'],
subject: 'Receipt',
text: 'Thanks for your purchase',
tags: [{ name: 'category', value: 'receipt' }],
},
],
},
});

expect(result.isError).toBeFalsy();
expect(batchSend).toHaveBeenCalledWith(
[
expect.objectContaining({
tags: [{ name: 'category', value: 'receipt' }],
}),
],
undefined,
);
});
});