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