Skip to content
Open
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
10 changes: 6 additions & 4 deletions src/tools/emails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ export function addEmailTools(
...(replierEmailAddresses.length === 0
? {
replyTo: z
.array(z.email())
.array(z.string())
.optional()
.describe(
'Optional email addresses for the email readers to reply to. You MUST ask the user for this parameter. Under no circumstance provide it yourself',
'Optional email addresses for the email readers to reply to (e.g. "support@example.com" or "Support Team <support@example.com>"). You MUST ask the user for this parameter. Under no circumstance provide it yourself',
),
}
: {}),
Expand Down Expand Up @@ -1005,9 +1005,11 @@ export function addEmailTools(
'Sender email address. Falls back to the configured default sender if not provided.',
),
replyTo: z
.array(z.email())
.array(z.string())
.optional()
.describe('Reply-to email addresses'),
.describe(
'Reply-to email addresses (e.g. "support@example.com" or "Support Team <support@example.com>")',
),
cc: z.array(z.email()).optional().describe('CC email addresses'),
bcc: z
.array(z.email())
Expand Down
64 changes: 64 additions & 0 deletions tests/tools/emails.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,70 @@ describe('send-email from address format', () => {
});
});

describe('replyTo address format', () => {
beforeEach(() => {
vi.clearAllMocks();
send.mockResolvedValue({
data: { id: 'email_1' },
error: null,
});
batchSend.mockResolvedValue({
data: { data: [{ id: 'email_1' }] },
error: null,
});
});

it.each([
'support@example.com',
'Support Team <support@example.com>',
])('passes replyTo through send-email: %s', async (replyTo) => {
const client = await makeClient();
const result = await client.callTool({
name: 'send-email',
arguments: {
from: 'onboarding@resend.dev',
to: ['delivered@resend.dev'],
replyTo: [replyTo],
subject: 'hello',
text: 'world',
},
});

expect(result.isError).toBeFalsy();
expect(send).toHaveBeenCalledWith(
expect.objectContaining({ replyTo: [replyTo] }),
undefined,
);
});

it.each([
'support@example.com',
'Support Team <support@example.com>',
])('passes replyTo through send-batch-emails: %s', async (replyTo) => {
const client = await makeClient();
const result = await client.callTool({
name: 'send-batch-emails',
arguments: {
emails: [
{
from: 'onboarding@resend.dev',
to: ['delivered@resend.dev'],
replyTo: [replyTo],
subject: 'hello',
text: 'world',
},
],
},
});

expect(result.isError).toBeFalsy();
expect(batchSend).toHaveBeenCalledWith(
[expect.objectContaining({ replyTo: [replyTo] })],
undefined,
);
});
});

describe('send-email idempotency key', () => {
beforeEach(() => {
vi.clearAllMocks();
Expand Down