Skip to main content
Glama

get_draft_emails

Retrieve draft emails from Microsoft Outlook to review, edit, or send pending messages.

Instructions

Get draft emails list

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
countNoNumber of draft emails to retrieve

Implementation Reference

  • MCP server request handler case for 'get_draft_emails': parses input count, fetches drafts via OutlookManager, and returns formatted markdown list of draft emails.
    case 'get_draft_emails': {
      const count = (args as any)?.count || 10;
      const drafts = await outlookManager.getDraftEmails(count);
      return {
        content: [
          {
            type: 'text',
            text: `šŸ“‚ **Draft Email Overview**\nTotal: ${drafts.length} drafts\n\nšŸ“ **Draft Email List:**\n` + 
                 drafts.map((draft, index) => 
                   `${index + 1}. **${draft.subject}**\n   From: ${draft.sender}\n   Time: ${draft.receivedTime}\n   EntryID: ${draft.id}\n   StoreID: ${draft.storeId || 'N/A'}\n   Preview: ${draft.body?.substring(0, 100)}...\n`
                 ).join('\n')
          },
        ],
      };
    }
  • Core handler method getDraftEmails that retrieves draft emails from Outlook Drafts folder (folder type 16) using the shared getEmailsFromFolder helper.
    async getDraftEmails(count: number = 10): Promise<EmailMessage[]> {
      return this.getEmailsFromFolder(16, count, "[LastModificationTime]"); // 16 = Drafts
    }
  • Shared helper function getEmailsFromFolder executes PowerShell script using Outlook COM interop to fetch, parse, and return EmailMessage[] from any specified folder (Inbox=6, Sent=5, Drafts=16), with sorting, limiting, cleaning, and fallback handling.
    private async getEmailsFromFolder(folderType: number, count: number = 10, sortBy: string = "[ReceivedTime]"): Promise<EmailMessage[]> {
      const script = `
        try {
          Add-Type -AssemblyName "Microsoft.Office.Interop.Outlook" -ErrorAction Stop
          $outlook = New-Object -ComObject Outlook.Application -ErrorAction Stop
          $namespace = $outlook.GetNamespace("MAPI")
          $folder = $namespace.GetDefaultFolder(${folderType})
          
          if ($folder.Items.Count -eq 0) {
            Write-Output "[]"
            exit 0
          }
          
          $items = $folder.Items
          $items.Sort("${sortBy}", $true)
          
          $emails = @()
          $counter = 0
          
          foreach ($item in $items) {
            if ($counter -ge ${count}) { break }
            
            try {
              $subject = if ($item.Subject) { $item.Subject.ToString() -replace '[\\x00-\\x1F\\x7F]', '' } else { "No Subject" }
              $sender = if ($item.SenderEmailAddress) { $item.SenderEmailAddress.ToString() -replace '[\\x00-\\x1F\\x7F]', '' } else { "Unknown" }
              $body = if ($item.Body) { 
                $bodyStr = $item.Body.ToString() -replace '[\\x00-\\x1F\\x7F]', ''
                if ($bodyStr.Length -gt 150) { $bodyStr.Substring(0, 150) + "..." } else { $bodyStr }
              } else { "" }
              
              $timeStamp = if ($item.SentOn -and ${folderType} -eq 5) { 
                $item.SentOn.ToString("yyyy-MM-dd HH:mm:ss") 
              } elseif ($item.ReceivedTime) { 
                $item.ReceivedTime.ToString("yyyy-MM-dd HH:mm:ss") 
              } else { 
                (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") 
              }
              
              $emails += [PSCustomObject]@{
                Id = if ($item.EntryID) { $item.EntryID.ToString() } else { "no-id-$counter" }
                StoreID = if ($item.Session -and $item.Session.DefaultStore -and $item.Session.DefaultStore.StoreID) { 
                  $item.Session.DefaultStore.StoreID.ToString() 
                } elseif ($item.Parent -and $item.Parent.StoreID) { 
                  $item.Parent.StoreID.ToString() 
                } else { 
                  try { $namespace.DefaultStore.StoreID.ToString() } catch { "" }
                }
                Subject = $subject
                Sender = $sender
                Recipients = @()
                Body = $body
                ReceivedTime = $timeStamp
                IsRead = if (${folderType} -eq 5) { $true } else { -not $item.UnRead }
                HasAttachments = $item.Attachments.Count -gt 0
              }
              
              $counter++
            } catch { $counter++; continue }
          }
          
          if ($emails.Count -eq 0) { Write-Output "[]" } 
          else { Write-Output ($emails | ConvertTo-Json -Depth 2 -Compress) }
          
        } catch {
          Write-Output ([PSCustomObject]@{ error = $_.Exception.Message; type = "OutlookConnectionError" } | ConvertTo-Json -Compress)
        }
      `;
    
      try {
        const result = await this.executePowerShell(script);
        if (!result || result.trim() === '') return [];
        
        const cleanResult = result.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, '').trim();
        const parsed = JSON.parse(cleanResult);
        
        if (parsed.error) throw new Error(`Outlook Error: ${parsed.error}`);
        
        const emailArray = Array.isArray(parsed) ? parsed : [parsed];
        return emailArray.map((item: any) => ({
          id: this.cleanText(item.Id || ''),
          storeId: this.cleanText(item.StoreID || ''),
          subject: this.cleanText(item.Subject || 'No Subject'),
          sender: this.cleanText(item.Sender || 'Unknown'),
          recipients: [],
          body: this.cleanText(item.Body || ''),
          receivedTime: new Date(item.ReceivedTime),
          isRead: Boolean(item.IsRead),
          hasAttachments: Boolean(item.HasAttachments)
        }));
        
      } catch (error) {
        console.error('Email fetch failed:', error);
        return [{
          id: 'fallback-1',
          storeId: '',
          subject: 'Email content unavailable',
          sender: 'system@outlook.com',
          recipients: [],
          body: 'Unable to retrieve email content.',
          receivedTime: new Date(),
          isRead: true,
          hasAttachments: false
        }];
      }
    }
  • src/index.ts:184-197 (registration)
    Tool registration in ListToolsRequestSchema handler: defines name, description, and inputSchema for get_draft_emails.
    {
      name: "get_draft_emails",
      description: "Get draft emails list",
      inputSchema: {
        type: "object",
        properties: {
          count: {
            type: "number",
            description: "Number of draft emails to retrieve",
            default: 10
          }
        }
      }
    },
  • TypeScript interface EmailMessage defining the structure of email objects returned by getDraftEmails and other email fetching methods.
    export interface EmailMessage {
      id: string;
      storeId?: string;
      subject: string;
      sender: string;
      recipients: string[];
      body: string;
      receivedTime: Date;
      isRead: boolean;
      hasAttachments: boolean;
    }
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. The description only states what the tool does ('Get draft emails list') without mentioning any behavioral traits like whether it's read-only, if it requires authentication, how results are ordered, pagination behavior, or error conditions. For a tool with zero annotation coverage, this is a significant gap in transparency.

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

Conciseness4/5

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

The description is extremely concise at just three words, which is appropriate for a simple retrieval tool. It's front-loaded with the core purpose. However, it could be slightly more informative without sacrificing conciseness, such as specifying it retrieves a list rather than just stating 'Get draft emails list'.

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 doesn't explain what the return value looks like (e.g., list format, email fields included), ordering, pagination, or error handling. For a tool that presumably returns data, the absence of output information combined with minimal behavioral disclosure makes this description inadequate.

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 the single parameter 'count' clearly documented in the schema as 'Number of draft emails to retrieve' with a default value of 10. The description doesn't add any parameter information beyond what's already in the schema. With high schema coverage and only one parameter, the baseline score of 3 is appropriate.

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

Purpose3/5

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

The description 'Get draft emails list' clearly states the verb 'Get' and resource 'draft emails list', making the basic purpose understandable. However, it doesn't differentiate from sibling tools like 'search_draft_emails' or 'get_inbox_emails', leaving ambiguity about scope and filtering capabilities. The purpose is stated but lacks specificity about what kind of retrieval this performs.

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?

No guidance is provided about when to use this tool versus alternatives like 'search_draft_emails' or 'get_inbox_emails'. The description doesn't mention any context, prerequisites, or exclusions for usage. While the name implies it's for draft emails specifically, there's no explicit comparison with similar tools in the sibling list.

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/cqyefeng119/windows-outlook-mcp'

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