Skip to main content
Glama

gmail_remove_label_from_messages

Remove labels from Gmail messages by specifying message IDs or using search queries to organize your inbox efficiently.

Instructions

Remove a label from one or more messages. Can specify messages by IDs or by search query.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
label_nameNoName of the label to remove. Provide either label_name or label_id.
label_idNoID of the label to remove. Provide either label_name or label_id.
message_idsNoComma-separated list of message IDs to remove the label from.
queryNoGmail search query to find messages. Alternative to message_ids.
max_messagesNoMaximum messages to modify when using query. Default 100, max 500.
confirmYesMust be true to actually modify. Set false to preview.

Implementation Reference

  • Tool registration in GMAIL_TOOLS list, including full input schema definition. This Tool object is returned by list_tools() for MCP server registration.
    Tool( name="gmail_remove_label_from_messages", description="Remove a label from one or more messages. Can specify messages by IDs or by search query.", inputSchema={ "type": "object", "properties": { "label_name": { "type": "string", "description": "Name of the label to remove. Provide either label_name or label_id." }, "label_id": { "type": "string", "description": "ID of the label to remove. Provide either label_name or label_id." }, "message_ids": { "type": "string", "description": "Comma-separated list of message IDs to remove the label from." }, "query": { "type": "string", "description": "Gmail search query to find messages. Alternative to message_ids." }, "max_messages": { "type": "integer", "description": "Maximum messages to modify when using query. Default 100, max 500." }, "confirm": { "type": "boolean", "description": "Must be true to actually modify. Set false to preview." } }, "required": ["confirm"] },
  • Main handler function for gmail_remove_label_from_messages tool (shared with add_label). Dispatched from handle_call_tool. Validates args, finds label ID, resolves message IDs from query or list, handles confirmation preview, calls GmailClient.modify_message_labels with remove_label_ids.
    async def _handle_label_modify(client: GmailClient, arguments: dict[str, Any], add: bool) -> list[TextContent]: """Handle add/remove label from messages. Args: client: The Gmail client instance. arguments: Tool arguments dictionary. add: True to add label, False to remove label. Returns: list[TextContent]: Response text. """ label_id = arguments.get("label_id") label_name = arguments.get("label_name") message_ids_str = arguments.get("message_ids", "") query = arguments.get("query") max_messages = min(arguments.get("max_messages", 100), 500) confirm = arguments.get("confirm", False) action_verb = "add" if add else "remove" action_prep = "to" if add else "from" if not label_id and not label_name: return [TextContent(type="text", text="Error: Provide either label_id or label_name.")] if not message_ids_str and not query: return [TextContent(type="text", text="Error: Provide either message_ids or query.")] # Find label by name if ID not provided if not label_id: label = await client.find_label_by_name(label_name) if not label: return [TextContent(type="text", text=f"Error: Label not found: {label_name}")] label_id = label["id"] label_display = label["name"] else: label_display = label_name or label_id # Get message IDs from string or query if message_ids_str: message_ids = [mid.strip() for mid in message_ids_str.split(",") if mid.strip()] else: search_results = await client.search_emails(query, max_messages) if not search_results: return [TextContent(type="text", text=f"No emails found matching query: {query}")] message_ids = [email.id for email in search_results] if not confirm: return [TextContent( type="text", text=f"Preview: Would {action_verb} label '{label_display}' {action_prep} {len(message_ids)} message(s). Set confirm=true to proceed." )] if add: result = await client.modify_message_labels(message_ids, add_label_ids=[label_id]) else: result = await client.modify_message_labels(message_ids, remove_label_ids=[label_id]) if result["success"] > 0: return [TextContent( type="text", text=f"Success: {'Added' if add else 'Removed'} label '{label_display}' {action_prep} {result['success']} message(s)." + (f" Errors: {result['errors']}" if result['errors'] else "") )] else: return [TextContent(type="text", text=f"Error: Failed to modify labels. {result['errors']}")]
  • Core GmailClient method that executes the Gmail API batchModify call to remove labels from messages using Gmail API v1 messages.batchModify with removeLabelIds.
    async def modify_message_labels( self, message_ids: list[str], add_label_ids: list[str] | None = None, remove_label_ids: list[str] | None = None ) -> dict: """Add or remove labels from messages. Args: message_ids: List of message IDs to modify add_label_ids: Label IDs to add to the messages remove_label_ids: Label IDs to remove from the messages Returns: Dict with success count and errors """ if not message_ids: return {"success": 0, "errors": [], "message": "No message IDs provided"} if not add_label_ids and not remove_label_ids: return {"success": 0, "errors": [], "message": "No labels to add or remove"} results = {"success": 0, "errors": []} try: body = {"ids": message_ids} if add_label_ids: body["addLabelIds"] = add_label_ids if remove_label_ids: body["removeLabelIds"] = remove_label_ids # Use batchModify for efficiency if len(message_ids) <= 1000: self.service.users().messages().batchModify( userId="me", body=body ).execute() results["success"] = len(message_ids) else: # Process in batches of 1000 for i in range(0, len(message_ids), 1000): batch = message_ids[i:i+1000] batch_body = body.copy() batch_body["ids"] = batch self.service.users().messages().batchModify( userId="me", body=batch_body ).execute() results["success"] += len(batch) except HttpError as e: logger.error(f"Failed to modify message labels: {e}") results["errors"].append(str(e)) return results
  • Helper method used by handler to resolve label_name to label_id by searching existing labels.
    async def find_label_by_name(self, name: str) -> dict | None: """Find a label by name (case-insensitive). Args: name: Label name to search for Returns: Label dict or None if not found """ labels = await self.get_labels() name_lower = name.lower() for label in labels: if label.get("name", "").lower() == name_lower: return label return None

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