Skip to main content
Glama

send_email

Send emails through Fastmail with options for recipients, subject, body content, and email organization.

Instructions

Send an email

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
toYesRecipient email addresses
ccNoCC email addresses (optional)
bccNoBCC email addresses (optional)
fromNoSender email address (optional, defaults to account primary email)
mailboxIdNoMailbox ID to save the email to (optional, defaults to Drafts folder)
subjectYesEmail subject
textBodyNoPlain text body (optional)
htmlBodyNoHTML body (optional)

Implementation Reference

  • src/index.ts:178-222 (registration)
    Registration of the 'send_email' MCP tool, including name, description, and detailed input schema definition.
    { name: 'send_email', description: 'Send an email', inputSchema: { type: 'object', properties: { to: { type: 'array', items: { type: 'string' }, description: 'Recipient email addresses', }, cc: { type: 'array', items: { type: 'string' }, description: 'CC email addresses (optional)', }, bcc: { type: 'array', items: { type: 'string' }, description: 'BCC email addresses (optional)', }, from: { type: 'string', description: 'Sender email address (optional, defaults to account primary email)', }, mailboxId: { type: 'string', description: 'Mailbox ID to save the email to (optional, defaults to Drafts folder)', }, subject: { type: 'string', description: 'Email subject', }, textBody: { type: 'string', description: 'Plain text body (optional)', }, htmlBody: { type: 'string', description: 'HTML body (optional)', }, }, required: ['to', 'subject'], }, },
  • MCP tool handler for 'send_email': extracts and validates arguments, calls JmapClient.sendEmail(), and returns success response with submission ID.
    case 'send_email': { const { to, cc, bcc, from, mailboxId, subject, textBody, htmlBody } = args as any; if (!to || !Array.isArray(to) || to.length === 0) { throw new McpError(ErrorCode.InvalidParams, 'to field is required and must be a non-empty array'); } if (!subject) { throw new McpError(ErrorCode.InvalidParams, 'subject is required'); } if (!textBody && !htmlBody) { throw new McpError(ErrorCode.InvalidParams, 'Either textBody or htmlBody is required'); } const submissionId = await client.sendEmail({ to, cc, bcc, from, mailboxId, subject, textBody, htmlBody, }); return { content: [ { type: 'text', text: `Email sent successfully. Submission ID: ${submissionId}`, }, ], }; }
  • JmapClient.sendEmail(): core helper function implementing JMAP protocol calls (Email/set to create draft, EmailSubmission/set to submit, automatic move to Sent folder on success). Handles identity validation, mailbox resolution, and error cases.
    async sendEmail(email: { to: string[]; cc?: string[]; bcc?: string[]; subject: string; textBody?: string; htmlBody?: string; from?: string; mailboxId?: string; }): Promise<string> { const session = await this.getSession(); // Get all identities to validate from address const identities = await this.getIdentities(); if (!identities || identities.length === 0) { throw new Error('No sending identities found'); } // Determine which identity to use let selectedIdentity; if (email.from) { // Validate that the from address matches an available identity selectedIdentity = identities.find(id => id.email.toLowerCase() === email.from?.toLowerCase() ); if (!selectedIdentity) { throw new Error('From address is not verified for sending. Choose one of your verified identities.'); } } else { // Use default identity selectedIdentity = identities.find(id => id.mayDelete === false) || identities[0]; } const fromEmail = selectedIdentity.email; // Get the mailbox IDs we need const mailboxes = await this.getMailboxes(); const draftsMailbox = mailboxes.find(mb => mb.role === 'drafts') || mailboxes.find(mb => mb.name.toLowerCase().includes('draft')); const sentMailbox = mailboxes.find(mb => mb.role === 'sent') || mailboxes.find(mb => mb.name.toLowerCase().includes('sent')); if (!draftsMailbox) { throw new Error('Could not find Drafts mailbox to save email'); } if (!sentMailbox) { throw new Error('Could not find Sent mailbox to move email after sending'); } // Use provided mailboxId or default to drafts for initial creation const initialMailboxId = email.mailboxId || draftsMailbox.id; // Ensure we have at least one body type if (!email.textBody && !email.htmlBody) { throw new Error('Either textBody or htmlBody must be provided'); } const initialMailboxIds: Record<string, boolean> = {}; initialMailboxIds[initialMailboxId] = true; const sentMailboxIds: Record<string, boolean> = {}; sentMailboxIds[sentMailbox.id] = true; const emailObject = { mailboxIds: initialMailboxIds, keywords: { $draft: true }, from: [{ email: fromEmail }], to: email.to.map(addr => ({ email: addr })), cc: email.cc?.map(addr => ({ email: addr })) || [], bcc: email.bcc?.map(addr => ({ email: addr })) || [], subject: email.subject, textBody: email.textBody ? [{ partId: 'text', type: 'text/plain' }] : undefined, htmlBody: email.htmlBody ? [{ partId: 'html', type: 'text/html' }] : undefined, bodyValues: { ...(email.textBody && { text: { value: email.textBody } }), ...(email.htmlBody && { html: { value: email.htmlBody } }) } }; const request: JmapRequest = { using: ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:mail', 'urn:ietf:params:jmap:submission'], methodCalls: [ ['Email/set', { accountId: session.accountId, create: { draft: emailObject } }, 'createEmail'], ['EmailSubmission/set', { accountId: session.accountId, create: { submission: { emailId: '#draft', identityId: selectedIdentity.id, envelope: { mailFrom: { email: fromEmail }, rcptTo: email.to.map(addr => ({ email: addr })) } } }, onSuccessUpdateEmail: { '#submission': { mailboxIds: sentMailboxIds, keywords: { $seen: true } } } }, 'submitEmail'] ] }; const response = await this.makeRequest(request); // Check if email creation was successful const emailResult = response.methodResponses[0][1]; if (emailResult.notCreated && emailResult.notCreated.draft) { throw new Error('Failed to create email. Please check inputs and try again.'); } // Check if email submission was successful const submissionResult = response.methodResponses[1][1]; if (submissionResult.notCreated && submissionResult.notCreated.submission) { throw new Error('Failed to submit email. Please try again later.'); } return submissionResult.created?.submission?.id || 'unknown'; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MadLlama25/fastmail-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server