Skip to main content
Glama

gmail_send_email

Send emails or reply to threads through Gmail with confirmation required before sending.

Instructions

Send an email. Can send new emails or reply to existing threads. Requires confirmation before sending.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
toYesComma-separated list of recipient email addresses.
subjectYesEmail subject line.
bodyYesEmail body text in plain text format.
ccNoComma-separated list of CC recipient email addresses. Optional.
bccNoComma-separated list of BCC recipient email addresses. Optional.
reply_to_message_idNoMessage ID to reply to for threading. Optional.
confirmYesMust be true to actually send the email. Set false to preview.

Implementation Reference

  • Core implementation of the gmail_send_email tool in GmailClient class. Constructs MIME message, handles reply-to threading by fetching original message headers, base64 encodes, and sends via Gmail API users.messages.send.
    async def send_email( self, to: list[str], subject: str, body: str, cc: list[str] | None = None, bcc: list[str] | None = None, reply_to_message_id: str | None = None, ) -> dict: """Send an email. Args: to: List of recipient email addresses subject: Email subject body: Email body (plain text) cc: Optional CC recipients bcc: Optional BCC recipients reply_to_message_id: Optional message ID to reply to (for threading) Returns: Dict with sent message info or error """ try: # Create the email message message = MIMEText(body) message['to'] = ', '.join(to) message['subject'] = subject if cc: message['cc'] = ', '.join(cc) if bcc: message['bcc'] = ', '.join(bcc) # Handle reply threading thread_id = None if reply_to_message_id: # Get the original message to get thread ID and references try: original = self.service.users().messages().get( userId="me", id=reply_to_message_id, format="metadata", metadataHeaders=["Message-ID", "References", "In-Reply-To"] ).execute() thread_id = original.get("threadId") # Get original Message-ID for threading headers headers = original.get("payload", {}).get("headers", []) original_message_id = None references = None for header in headers: if header["name"].lower() == "message-id": original_message_id = header["value"] elif header["name"].lower() == "references": references = header["value"] # Set threading headers if original_message_id: message['In-Reply-To'] = original_message_id if references: message['References'] = f"{references} {original_message_id}" else: message['References'] = original_message_id except HttpError as e: logger.warning(f"Could not get original message for threading: {e}") # Encode the message raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode('utf-8') # Send the message body_data = {'raw': raw_message} if thread_id: body_data['threadId'] = thread_id sent_message = self.service.users().messages().send( userId="me", body=body_data ).execute() logger.info(f"Email sent successfully. Message ID: {sent_message['id']}") return { "success": True, "message_id": sent_message["id"], "thread_id": sent_message.get("threadId"), "to": to, "subject": subject, } except HttpError as e: logger.error(f"Failed to send email: {e}") return { "success": False, "error": str(e), "to": to, "subject": subject, }
  • MCP tool dispatcher handler for 'gmail_send_email'. Validates input arguments, provides preview mode if confirm=false, and delegates to GmailClient.send_email when confirmed.
    elif name == "gmail_send_email": to = arguments.get("to", []) subject = arguments.get("subject", "") body = arguments.get("body", "") cc = arguments.get("cc", []) bcc = arguments.get("bcc", []) reply_to_message_id = arguments.get("reply_to_message_id") confirm = arguments.get("confirm", False) # Validate required fields if not to: return [TextContent(type="text", text="Error: 'to' recipients are required.")] if not subject: return [TextContent(type="text", text="Error: 'subject' is required.")] if not body: return [TextContent(type="text", text="Error: 'body' is required.")] if not confirm: # Preview mode lines = [ "⚠️ Preview: The following email would be sent:\n", f"To: {', '.join(to)}", ] if cc: lines.append(f"CC: {', '.join(cc)}") if bcc: lines.append(f"BCC: {', '.join(bcc)}") lines.append(f"Subject: {subject}") if reply_to_message_id: lines.append(f"Reply to message: {reply_to_message_id}") lines.append(f"\n--- Body ---\n{body[:500]}") if len(body) > 500: lines.append(f"\n... ({len(body) - 500} more characters)") lines.append("\n\nTo send this email, call this tool again with confirm=true") return [TextContent(type="text", text="\n".join(lines))] else: # Actually send the email result = await client.send_email( to=to, subject=subject, body=body, cc=cc if cc else None, bcc=bcc if bcc else None, reply_to_message_id=reply_to_message_id, ) if result["success"]: return [TextContent( type="text", text=f"✅ Email sent successfully!\n\nTo: {', '.join(result['to'])}\nSubject: {result['subject']}\nMessage ID: {result['message_id']}" )] else: return [TextContent( type="text", text=f"❌ Failed to send email.\n\nError: {result['error']}" )]
  • Tool registration in list_tools() decorator, including name, description, and full inputSchema for parameter validation.
    Tool( name="gmail_send_email", description="Send an email. Can send new emails or reply to existing threads.", inputSchema={ "type": "object", "properties": { "to": { "type": "array", "items": {"type": "string"}, "description": "List of recipient email addresses", }, "subject": { "type": "string", "description": "Email subject line", }, "body": { "type": "string", "description": "Email body text (plain text)", }, "cc": { "type": "array", "items": {"type": "string"}, "description": "CC recipients (optional)", }, "bcc": { "type": "array", "items": {"type": "string"}, "description": "BCC recipients (optional)", }, "reply_to_message_id": { "type": "string", "description": "Message ID to reply to (optional, for threading)", }, "confirm": { "type": "boolean", "description": "Must be true to actually send the email. Set to false to preview.", "default": False, }, }, "required": ["to", "subject", "body"], }, ),
  • JSON schema definition for gmail_send_email tool inputs, defining properties, descriptions, defaults, and required fields.
    inputSchema={ "type": "object", "properties": { "to": { "type": "array", "items": {"type": "string"}, "description": "List of recipient email addresses", }, "subject": { "type": "string", "description": "Email subject line", }, "body": { "type": "string", "description": "Email body text (plain text)", }, "cc": { "type": "array", "items": {"type": "string"}, "description": "CC recipients (optional)", }, "bcc": { "type": "array", "items": {"type": "string"}, "description": "BCC recipients (optional)", }, "reply_to_message_id": { "type": "string", "description": "Message ID to reply to (optional, for threading)", }, "confirm": { "type": "boolean", "description": "Must be true to actually send the email. Set to false to preview.", "default": False, }, }, "required": ["to", "subject", "body"], },

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/murphy360/mcp_gmail'

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