Skip to main content
Glama

gmail_mark_as_read_by_query

Mark Gmail emails matching search queries as read. Use Gmail query syntax to target specific messages, with confirmation required for changes. Preview results before applying.

Instructions

Mark emails matching a search query as read. Use Gmail query syntax. Requires confirmation.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesGmail search query to find emails to mark as read. Examples: 'from:newsletter@example.com', 'older_than:7d is:unread'.
max_emailsNoMaximum number of emails to mark as read. Default 100, max 500.
confirmYesMust be true to actually mark as read. Set false to preview what would be marked.

Implementation Reference

  • Core implementation: Searches for unread emails matching the Gmail query (limited to max_emails), retrieves their IDs, and marks them as read by calling mark_as_read.
    async def mark_as_read_by_query(self, query: str, max_emails: int = 100) -> dict:
        """Mark emails matching a query as read.
        
        Args:
            query: Gmail search query (e.g., "from:newsletter@example.com", "older_than:7d")
            max_emails: Maximum number of emails to mark as read (safety limit)
            
        Returns:
            Dict with success count, matched count, and any errors
        """
        try:
            # First, find matching emails
            results = (
                self.service.users()
                .messages()
                .list(userId="me", q=f"{query} is:unread", maxResults=max_emails)
                .execute()
            )
            
            messages = results.get("messages", [])
            if not messages:
                return {
                    "matched": 0,
                    "success": 0,
                    "errors": [],
                    "message": "No unread emails matched the query"
                }
            
            message_ids = [msg["id"] for msg in messages]
            
            # Mark them as read
            mark_result = await self.mark_as_read(message_ids)
            mark_result["matched"] = len(messages)
            
            # Check if there might be more
            if len(messages) == max_emails:
                mark_result["message"] = f"Marked {mark_result['success']} emails as read. There may be more matching emails (limit was {max_emails})."
            else:
                mark_result["message"] = f"Marked {mark_result['success']} emails as read."
                
            return mark_result
            
        except HttpError as e:
            logger.error(f"Failed to search and mark emails: {e}")
            return {"matched": 0, "success": 0, "errors": [str(e)], "message": f"Error: {e}"}
  • MCP tool dispatch handler: Parses arguments, provides preview if confirm=false by searching and listing matching emails, otherwise delegates to GmailClient.mark_as_read_by_query
    elif name == "gmail_mark_as_read_by_query":
        query = arguments.get("query", "")
        max_emails = min(arguments.get("max_emails", 100), 500)
        confirm = arguments.get("confirm", False)
        
        if not query:
            return [TextContent(type="text", text="Error: query is required.")]
        
        if not confirm:
            # Preview mode - show what would be marked
            search_results = await client.search_emails(f"{query} is:unread", max_emails)
            if not search_results:
                return [TextContent(type="text", text=f"No unread emails match the query: {query}")]
            
            lines = [f"Preview: {len(search_results)} email(s) would be marked as read:\n"]
            for email in search_results[:20]:
                lines.append(f"- {email.subject}")
                lines.append(f"  From: {email.sender.email}")
                lines.append(f"  Date: {email.date.strftime('%Y-%m-%d %H:%M')}")
                lines.append("")
            
            if len(search_results) > 20:
                lines.append(f"... and {len(search_results) - 20} more\n")
            
            lines.append("Set confirm=true to proceed.")
            return [TextContent(type="text", text="\n".join(lines))]
        else:
            result = await client.mark_as_read_by_query(query, max_emails)
            return [TextContent(
                type="text",
                text=f"Success: {result['message']}\nMatched: {result['matched']}, Marked as read: {result['success']}"
                + (f", Errors: {result['errors']}" if result['errors'] else "")
            )]
  • Tool registration in GMAIL_TOOLS list: Defines the tool name, description, and JSON schema for MCP server.
        name="gmail_mark_as_read_by_query",
        description="Mark emails matching a search query as read. Use Gmail query syntax. Requires confirmation.",
        inputSchema={
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Gmail search query to find emails to mark as read. Examples: 'from:newsletter@example.com', 'older_than:7d is:unread'."
                },
                "max_emails": {
                    "type": "integer",
                    "description": "Maximum number of emails to mark as read. Default 100, max 500."
                },
                "confirm": {
                    "type": "boolean",
                    "description": "Must be true to actually mark as read. Set false to preview what would be marked."
                }
            },
            "required": ["query", "confirm"]
        },
    ),
  • Supporting function: Batch removes the 'UNREAD' label from the specified message IDs using Gmail API batchModify.
    async def mark_as_read(self, message_ids: list[str]) -> dict:
        """Mark one or more emails as read by removing the UNREAD label.
        
        Args:
            message_ids: List of Gmail message IDs to mark as read
            
        Returns:
            Dict with success count and any errors
        """
        if not message_ids:
            return {"success": 0, "errors": [], "message": "No message IDs provided"}
        
        results = {"success": 0, "errors": []}
        
        try:
            # Use batchModify for efficiency (up to 1000 at a time)
            if len(message_ids) <= 1000:
                self.service.users().messages().batchModify(
                    userId="me",
                    body={
                        "ids": message_ids,
                        "removeLabelIds": ["UNREAD"]
                    }
                ).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]
                    self.service.users().messages().batchModify(
                        userId="me",
                        body={
                            "ids": batch,
                            "removeLabelIds": ["UNREAD"]
                        }
                    ).execute()
                    results["success"] += len(batch)
                    
        except HttpError as e:
            logger.error(f"Failed to mark emails as read: {e}")
            results["errors"].append(str(e))
            
        return results

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