/**
* Send Email Tool
* Sends emails via OpenClaw
*/
import type { OpenClawClient } from '../openclaw-client.js';
import type { SendEmailParams } from '../types.js';
/**
* Input schema for send_email tool
*/
export const SendEmailInputSchema = {
type: 'object',
properties: {
to: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'Recipient email address or list of addresses',
},
subject: {
type: 'string',
description: 'Email subject line',
},
body: {
type: 'string',
description: 'Email body content',
},
cc: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'CC recipients (optional)',
},
bcc: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'BCC recipients (optional)',
},
html: {
type: 'boolean',
description: 'Whether the body is HTML format (default: false)',
default: false,
},
},
required: ['to', 'subject', 'body'],
};
/**
* Normalize email to array
*/
function normalizeEmail(email: string | string[]): string[] {
return Array.isArray(email) ? email : [email];
}
/**
* Validate email format
*/
function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
/**
* Validate email addresses
*/
function validateEmails(
emails: string[],
fieldName: string
): { valid: boolean; error?: string } {
if (emails.length === 0) {
return { valid: false, error: `${fieldName} cannot be empty` };
}
for (const email of emails) {
if (!isValidEmail(email)) {
return { valid: false, error: `Invalid email format in ${fieldName}: ${email}` };
}
}
return { valid: true };
}
/**
* Execute the send_email tool
*/
export async function executeSendEmail(
client: OpenClawClient,
args: SendEmailParams
) {
try {
// Validate required fields
const to = normalizeEmail(args.to);
const toValidation = validateEmails(to, 'to');
if (!toValidation.valid) {
return {
content: [
{
type: 'text',
text: JSON.stringify({ error: toValidation.error }, null, 2),
},
],
isError: true,
};
}
if (!args.subject || args.subject.trim() === '') {
return {
content: [
{
type: 'text',
text: JSON.stringify({ error: 'Subject is required' }, null, 2),
},
],
isError: true,
};
}
if (!args.body || args.body.trim() === '') {
return {
content: [
{
type: 'text',
text: JSON.stringify({ error: 'Email body is required' }, null, 2),
},
],
isError: true,
};
}
// Validate optional fields
if (args.cc) {
const cc = normalizeEmail(args.cc);
const ccValidation = validateEmails(cc, 'cc');
if (!ccValidation.valid) {
return {
content: [
{
type: 'text',
text: JSON.stringify({ error: ccValidation.error }, null, 2),
},
],
isError: true,
};
}
}
if (args.bcc) {
const bcc = normalizeEmail(args.bcc);
const bccValidation = validateEmails(bcc, 'bcc');
if (!bccValidation.valid) {
return {
content: [
{
type: 'text',
text: JSON.stringify({ error: bccValidation.error }, null, 2),
},
],
isError: true,
};
}
}
// Prepare email parameters
const emailParams: SendEmailParams = {
to,
subject: args.subject,
body: args.body,
html: args.html ?? false,
};
if (args.cc) {
emailParams.cc = normalizeEmail(args.cc);
}
if (args.bcc) {
emailParams.bcc = normalizeEmail(args.bcc);
}
// Call the OpenClaw API
const response = await client.sendEmail(emailParams);
if (response.success) {
return {
content: [
{
type: 'text',
text: JSON.stringify(
{
success: true,
to: to,
subject: args.subject,
messageId: response.messageId,
message: 'Email sent successfully',
},
null,
2
),
},
],
};
} else {
return {
content: [
{
type: 'text',
text: JSON.stringify(
{
success: false,
to: to,
subject: args.subject,
error: response.error || 'Failed to send email',
},
null,
2
),
},
],
isError: true,
};
}
} catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify(
{
error: 'Unexpected error occurred',
details: error instanceof Error ? error.message : String(error),
},
null,
2
),
},
],
isError: true,
};
}
}
/**
* Tool definition for send_email
*/
export const SendEmailTool = {
name: 'send_email',
description: 'Send an email to one or more recipients with optional CC and BCC',
inputSchema: SendEmailInputSchema,
};