Skip to main content
Glama
ZilongXue

ClaudePost

by ZilongXue

search-emails

Search emails by date range or keywords in specific folders using ClaudePost. Retrieve relevant emails from 'inbox' or 'sent' folders efficiently.

Instructions

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

Input Schema

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

Implementation Reference

  • Executes the search-emails tool: selects folder, builds IMAP search criteria from dates and keyword, searches asynchronously, formats results as a table.
    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."
            )]
  • JSON schema for search-emails input parameters: start_date, end_date, keyword, folder.
    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"],
            },
        },
    },
  • Tool registration in list_tools(): defines name, description, and schema for search-emails.
    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"],
                },
            },
        },
    ),
  • Helper function that performs the actual IMAP email search, fetches messages, formats summaries, limits to MAX_EMAILS.
    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 to extract and format basic summary (id, from, date, subject) from raw email message data.
    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 lacks critical details: it doesn't specify whether this is a read-only operation, what permissions are required, how results are returned (e.g., pagination, format), or any rate limits. For a search tool with zero annotation coverage, this is a significant gap.

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 front-loads the core purpose ('search emails') and succinctly lists the search criteria. There's no wasted verbiage or redundancy, making it easy for an agent to parse 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 for a search tool. It doesn't explain what the tool returns (e.g., email summaries, IDs, full content), how results are structured, or any behavioral constraints. This leaves the agent with insufficient context to use the tool effectively beyond basic parameter input.

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%, with all parameters well-documented in the input schema (e.g., date formats, folder options, keyword usage). The description adds minimal value beyond the schema by implying date-range and keyword filtering but doesn't provide additional syntax or format details. 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 specific verbs ('search emails') and resources ('emails'), and specifies search criteria ('within a date range and/or with specific keywords'). However, it doesn't explicitly differentiate from sibling tools like 'count-daily-emails' or 'get-email-content', which prevents a perfect score.

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 content). There's no mention of prerequisites, exclusions, or comparative use cases, leaving the agent to infer usage from the purpose alone.

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

Related 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/ZilongXue/claude-post'

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