Skip to main content
Glama

search-emails

Search emails by date range or keywords to find specific messages in your inbox or sent folder. Use this tool to locate emails based on content or timeframe.

Instructions

Search emails within a date range and/or with specific keywords

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
start_dateNoStart date in YYYY-MM-DD format (optional)
end_dateNoEnd date in YYYY-MM-DD format (optional)
keywordNoKeyword to search in email subject and body (optional)
folderNoFolder to search in ('inbox' or 'sent', defaults to 'inbox')

Implementation Reference

  • Handler for 'search-emails' tool: parses arguments, builds IMAP search criteria from dates/keyword/folder, performs async search, formats and returns table of email summaries.
    if name == "search-emails":
        # 选择文件夹
        folder = arguments.get("folder", "inbox")  # 默认选择收件箱
        if folder == "sent":
            mail.select('"[Gmail]/Sent Mail"')  # 对于 Gmail
        else:
            mail.select("inbox")
        
        # Get optional parameters
        start_date = arguments.get("start_date")
        end_date = arguments.get("end_date")
        keyword = arguments.get("keyword")
        
        # If no dates provided, default to last 7 days
        if not start_date:
            start_date = datetime.now() - timedelta(days=7)
            start_date = start_date.strftime("%d-%b-%Y")
        else:
            start_date = datetime.strptime(start_date, "%Y-%m-%d").strftime("%d-%b-%Y")
            
        if not end_date:
            end_date = datetime.now().strftime("%d-%b-%Y")
        else:
            # Convert end_date to datetime object once
            end_date_obj = datetime.strptime(end_date, "%Y-%m-%d")
            end_date = end_date_obj.strftime("%d-%b-%Y")
        
        # Build search criteria
        if start_date == end_date:
            # If searching for a single day
            search_criteria = f'ON "{start_date}"'
        else:
            # Calculate next day using the already converted end_date_obj
            next_day = (end_date_obj + timedelta(days=1)).strftime("%d-%b-%Y")
            search_criteria = f'SINCE "{start_date}" BEFORE "{next_day}"'
            
        if keyword:
            # Fix: Properly combine keyword search with date criteria
            keyword_criteria = f'(OR SUBJECT "{keyword}" BODY "{keyword}")'
            search_criteria = f'({keyword_criteria} {search_criteria})'
        
        logging.debug(f"Search criteria: {search_criteria}")  # Add debug logging
        
        try:
            async with asyncio.timeout(SEARCH_TIMEOUT):
                email_list = await search_emails_async(mail, search_criteria)
                
            if not email_list:
                return [types.TextContent(
                    type="text",
                    text="No emails found matching the criteria."
                )]
            
            # Format the results as a table
            result_text = "Found emails:\n\n"
            result_text += "ID | From | Date | Subject\n"
            result_text += "-" * 80 + "\n"
            
            for email in email_list:
                result_text += f"{email['id']} | {email['from']} | {email['date']} | {email['subject']}\n"
            
            result_text += "\nUse get-email-content with an email ID to view the full content of a specific email."
            
            return [types.TextContent(
                type="text",
                text=result_text
            )]
            
        except asyncio.TimeoutError:
            return [types.TextContent(
                type="text",
                text="Search operation timed out. Please try with a more specific search criteria."
            )]
  • Registration of the 'search-emails' tool in the @server.list_tools() function, including name, description, and input schema.
    types.Tool(
        name="search-emails",
        description="Search emails within a date range and/or with specific keywords",
        inputSchema={
            "type": "object",
            "properties": {
                "start_date": {
                    "type": "string",
                    "description": "Start date in YYYY-MM-DD format (optional)",
                },
                "end_date": {
                    "type": "string",
                    "description": "End date in YYYY-MM-DD format (optional)",
                },
                "keyword": {
                    "type": "string",
                    "description": "Keyword to search in email subject and body (optional)",
                },
                "folder": {
                    "type": "string",
                    "description": "Folder to search in ('inbox' or 'sent', defaults to 'inbox')",
                    "enum": ["inbox", "sent"],
                },
            },
        },
    ),
  • JSON schema defining inputs for search-emails: optional start_date, end_date, keyword, folder (inbox/sent).
    inputSchema={
        "type": "object",
        "properties": {
            "start_date": {
                "type": "string",
                "description": "Start date in YYYY-MM-DD format (optional)",
            },
            "end_date": {
                "type": "string",
                "description": "End date in YYYY-MM-DD format (optional)",
            },
            "keyword": {
                "type": "string",
                "description": "Keyword to search in email subject and body (optional)",
            },
            "folder": {
                "type": "string",
                "description": "Folder to search in ('inbox' or 'sent', defaults to 'inbox')",
                "enum": ["inbox", "sent"],
            },
        },
    },
  • Helper function that performs the actual IMAP search using the criteria, fetches up to MAX_EMAILS emails, formats summaries using format_email_summary.
    async def search_emails_async(mail: imaplib.IMAP4_SSL, search_criteria: str) -> list[dict]:
        """Asynchronously search emails with timeout."""
        loop = asyncio.get_event_loop()
        try:
            _, messages = await loop.run_in_executor(None, lambda: mail.search(None, search_criteria))
            if not messages[0]:
                return []
                
            email_list = []
            for num in messages[0].split()[:MAX_EMAILS]:  # Limit to MAX_EMAILS
                _, msg_data = await loop.run_in_executor(None, lambda: mail.fetch(num, '(RFC822)'))
                email_list.append(format_email_summary(msg_data))
                
            return email_list
        except Exception as e:
            raise Exception(f"Error searching emails: {str(e)}")
  • Helper utility to parse raw IMAP email data into a summary dictionary with id, from, date, subject.
    def format_email_summary(msg_data: tuple) -> dict:
        """Format an email message into a summary dict with basic information."""
        email_body = email.message_from_bytes(msg_data[0][1])
        
        return {
            "id": msg_data[0][0].split()[0].decode(),  # Get the email ID
            "from": email_body.get("From", "Unknown"),
            "date": email_body.get("Date", "Unknown"),
            "subject": email_body.get("Subject", "No Subject"),
        }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions search functionality but fails to describe key behaviors like whether it returns full email content or summaries, pagination handling, rate limits, or authentication requirements. This leaves significant gaps for a search tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's function without unnecessary words. It is front-loaded with the core purpose and appropriately sized, making it easy to understand quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of annotations and output schema, the description is incomplete. It does not explain what the tool returns (e.g., email summaries, IDs, or full content), how results are structured, or any limitations like search scope or performance considerations. For a search tool with multiple parameters, this leaves critical context gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal value by implying date-range and keyword filtering but does not provide additional syntax, format details, or usage examples beyond what the schema specifies. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb ('search') and resource ('emails'), and specifies the search criteria ('within a date range and/or with specific keywords'). However, it does not explicitly differentiate from sibling tools like 'count-daily-emails' or 'get-email-content', which prevents a score of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'count-daily-emails' (for counting) or 'get-email-content' (for retrieving specific email details). It mentions search criteria but lacks explicit when/when-not instructions or prerequisites, such as whether it searches across all folders or requires authentication.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/meyannis/mcpemail'

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