Skip to main content
Glama
owen-nash

Fastmail MCP Server

by owen-nash

pin_email

Pin an email to keep it prominent, or unpin it to remove the flag. Provide the email ID and set pinned to true or false.

Instructions

Pin or unpin an email

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
emailIdYesID of the email to pin/unpin
pinnedNotrue to pin, false to unpin

Implementation Reference

  • Handler case for the 'pin_email' tool. Extracts emailId and pinned args, calls JmapClient.pinEmail(), and returns success message.
    case 'pin_email': {
      const { emailId, pinned = true } = args as any;
      if (!emailId) {
        throw new McpError(ErrorCode.InvalidParams, 'emailId is required');
      }
      const client = initializeClient();
      await client.pinEmail(emailId, pinned);
      return {
        content: [
          {
            type: 'text',
            text: `Email ${pinned ? 'pinned' : 'unpinned'} successfully`,
          },
        ],
      };
    }
  • Input schema registration for the 'pin_email' tool, defining emailId (required string) and pinned (optional boolean, default true).
    {
      name: 'pin_email',
      description: 'Pin or unpin an email',
      inputSchema: {
        type: 'object',
        properties: {
          emailId: {
            type: 'string',
            description: 'ID of the email to pin/unpin',
          },
          pinned: {
            type: 'boolean',
            description: 'true to pin, false to unpin',
            default: true,
          },
        },
        required: ['emailId'],
      },
    },
  • Core JMAP implementation of pinEmail. Uses Email/set to toggle the $flagged keyword (true to pin, null to unpin).
    async pinEmail(emailId: string, pinned: boolean = true): Promise<void> {
      const session = await this.getSession();
    
      const update: Record<string, any> = {};
      update[emailId] = pinned
        ? { 'keywords/$flagged': true }
        : { 'keywords/$flagged': null };
    
      const request: JmapRequest = {
        using: ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:mail'],
        methodCalls: [
          ['Email/set', {
            accountId: session.accountId,
            update
          }, 'pinEmail']
        ]
      };
    
      const response = await this.makeRequest(request);
      const result = this.getMethodResult(response, 0);
    
      if (result.notUpdated && result.notUpdated[emailId]) {
        throw new Error(`Failed to ${pinned ? 'pin' : 'unpin'} email.`);
      }
    }
  • src/index.ts:629-990 (registration)
    Tool registration within the ListToolsRequestSchema handler (lines 629-647 for pin_email definition).
          {
            name: 'pin_email',
            description: 'Pin or unpin an email',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email to pin/unpin',
                },
                pinned: {
                  type: 'boolean',
                  description: 'true to pin, false to unpin',
                  default: true,
                },
              },
              required: ['emailId'],
            },
          },
          {
            name: 'delete_email',
            description: 'Delete an email (move to trash)',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email to delete',
                },
              },
              required: ['emailId'],
            },
          },
          {
            name: 'move_email',
            description: 'Move an email to a different mailbox',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email to move',
                },
                targetMailboxId: {
                  type: 'string',
                  description: 'ID of the target mailbox',
                },
              },
              required: ['emailId', 'targetMailboxId'],
            },
          },
          {
            name: 'add_labels',
            description: 'Add labels (mailboxes) to an email without removing existing ones',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email to add labels to',
                },
                mailboxIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of mailbox IDs to add as labels',
                },
              },
              required: ['emailId', 'mailboxIds'],
            },
          },
          {
            name: 'remove_labels',
            description: 'Remove specific labels (mailboxes) from an email',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email to remove labels from',
                },
                mailboxIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of mailbox IDs to remove as labels',
                },
              },
              required: ['emailId', 'mailboxIds'],
            },
          },
          {
            name: 'get_email_attachments',
            description: 'Get list of attachments for an email',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email',
                },
              },
              required: ['emailId'],
            },
          },
          {
            name: 'download_attachment',
            description: 'Download an email attachment. If savePath is provided, saves the file to disk and returns the file path and size. Otherwise returns a download URL.',
            inputSchema: {
              type: 'object',
              properties: {
                emailId: {
                  type: 'string',
                  description: 'ID of the email',
                },
                attachmentId: {
                  type: 'string',
                  description: 'ID of the attachment',
                },
                savePath: {
                  type: 'string',
                  description: `File path to save the attachment to. Paths are restricted to ${getDownloadDir() || '~/Downloads/fastmail-mcp/'} (configurable via FASTMAIL_DOWNLOAD_DIR). Path traversal outside this directory is rejected for security. Parent directories will be created automatically.`,
                },
              },
              required: ['emailId', 'attachmentId'],
            },
          },
          {
            name: 'advanced_search',
            description: 'Advanced email search with multiple criteria',
            inputSchema: {
              type: 'object',
              properties: {
                query: {
                  type: 'string',
                  description: 'Text to search for in subject/body',
                },
                from: {
                  type: 'string',
                  description: 'Filter by sender email',
                },
                to: {
                  type: 'string',
                  description: 'Filter by recipient email',
                },
                subject: {
                  type: 'string',
                  description: 'Filter by subject',
                },
                hasAttachment: {
                  type: 'boolean',
                  description: 'Filter emails with attachments',
                },
                isUnread: {
                  type: 'boolean',
                  description: 'Filter unread emails',
                },
                isPinned: {
                  type: 'boolean',
                  description: 'Filter pinned emails',
                },
                mailboxId: {
                  type: 'string',
                  description: 'Search within specific mailbox',
                },
                after: {
                  type: 'string',
                  description: 'Emails after this date (ISO 8601)',
                },
                before: {
                  type: 'string',
                  description: 'Emails before this date (ISO 8601)',
                },
                limit: {
                  type: ['number', 'string'],
                  description: 'Maximum results (default: 50)',
                  default: 50,
                },
                ascending: {
                  type: 'boolean',
                  description: 'Sort oldest first instead of newest first (default: false)',
                },
              },
            },
          },
          {
            name: 'get_thread',
            description: 'Get all emails in a conversation thread',
            inputSchema: {
              type: 'object',
              properties: {
                threadId: {
                  type: 'string',
                  description: 'ID of the thread/conversation',
                },
              },
              required: ['threadId'],
            },
          },
          {
            name: 'get_mailbox_stats',
            description: 'Get statistics for a mailbox (unread count, total emails, etc.)',
            inputSchema: {
              type: 'object',
              properties: {
                mailboxId: {
                  type: 'string',
                  description: 'ID of the mailbox (optional, defaults to all mailboxes)',
                },
              },
            },
          },
          {
            name: 'get_account_summary',
            description: 'Get overall account summary with statistics',
            inputSchema: {
              type: 'object',
              properties: {},
            },
          },
          {
            name: 'bulk_mark_read',
            description: 'Mark multiple emails as read/unread',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to mark',
                },
                read: {
                  type: 'boolean',
                  description: 'true to mark as read, false as unread',
                  default: true,
                },
              },
              required: ['emailIds'],
            },
          },
          {
            name: 'bulk_pin',
            description: 'Pin or unpin multiple emails',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to pin/unpin',
                },
                pinned: {
                  type: 'boolean',
                  description: 'true to pin, false to unpin',
                  default: true,
                },
              },
              required: ['emailIds'],
            },
          },
          {
            name: 'bulk_move',
            description: 'Move multiple emails to a mailbox',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to move',
                },
                targetMailboxId: {
                  type: 'string',
                  description: 'ID of target mailbox',
                },
              },
              required: ['emailIds', 'targetMailboxId'],
            },
          },
          {
            name: 'bulk_delete',
            description: 'Delete multiple emails (move to trash)',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to delete',
                },
              },
              required: ['emailIds'],
            },
          },
          {
            name: 'bulk_add_labels',
            description: 'Add labels to multiple emails simultaneously',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to add labels to',
                },
                mailboxIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of mailbox IDs to add as labels',
                },
              },
              required: ['emailIds', 'mailboxIds'],
            },
          },
          {
            name: 'bulk_remove_labels',
            description: 'Remove labels from multiple emails simultaneously',
            inputSchema: {
              type: 'object',
              properties: {
                emailIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of email IDs to remove labels from',
                },
                mailboxIds: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of mailbox IDs to remove as labels',
                },
              },
              required: ['emailIds', 'mailboxIds'],
            },
          },
          {
            name: 'check_function_availability',
            description: 'Check which MCP functions are available based on account permissions',
            inputSchema: {
              type: 'object',
              properties: {},
            },
          },
          {
            name: 'test_bulk_operations',
            description: 'Test bulk operations by finding recent emails and performing safe operations (mark read/unread)',
            inputSchema: {
              type: 'object',
              properties: {
                dryRun: {
                  type: 'boolean',
                  description: 'If true, only shows what would be done without making changes (default: true)',
                  default: true,
                },
                limit: {
                  type: 'number',
                  description: 'Number of emails to test with (default: 3, max: 10)',
                  default: 3,
                },
              },
            },
          },
        ],
      };
    });
Behavior2/5

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

No annotations provided; description only states action without disclosing side effects (e.g., visual changes, reversibility) or behavioral traits beyond the basic operation.

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?

Extremely concise (5 words) with no waste. Appropriate for a simple tool, though lacks structural elements like examples or bullet points.

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

Completeness3/5

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

Adequate for a straightforward toggle operation, but missing details on return value or effect on email order/visibility. Could be more informative given no output schema.

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 covers all parameters with descriptions. The tool description adds no extra semantic value beyond the schema content.

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?

Clearly states action (pin/unpin) and resource (email). Distinguishes from sibling 'bulk_pin' by implication, but lacks explicit scope indication.

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 on when to use this tool versus alternatives like bulk_pin or other email operations. No context on prerequisites or conditions.

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/owen-nash/fastmail-mcp'

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