intentkit-mail
v1.0.1
Published
Email adapter for IntentKit — IMAP reading + SMTP sending via the provider system
Downloads
200
Maintainers
Readme
intentkit-mail
Email adapter for IntentKit — IMAP reading + SMTP sending via the provider system.
This is the adapter that drove IntentKit's entire provider architecture: letting AI agents (like Claude via Dispatch) read, search, and send email through MCP.
Install
npm install intentkit-mailQuick Start
import { defineFunction, IntentRegistry, createContext, serve, z } from 'intentkit';
import { createMailProvider, type MailClient } from 'intentkit-mail';
// Register your functions
const registry = new IntentRegistry().register(listEmails, readEmail, sendEmail);
// Create context (no database needed for email-only projects)
const context = await createContext({ events: true });
// Boot MCP server with mail provider
await serve({
name: 'my-mail-agent',
registry,
context,
providers: [
createMailProvider({
host: 'imap.gmail.com',
user: '[email protected]',
password: process.env.GMAIL_APP_PASSWORD!,
smtp: {
host: 'smtp.gmail.com',
},
}),
],
});Configuration
IMAP (required)
| Option | Default | Description |
|--------|---------|-------------|
| host | — | IMAP server hostname |
| port | 993 | IMAP port |
| user | — | Username / email address |
| password | — | Password or app-specific password |
| tls | true | Use TLS connection |
| name | 'mail' | Provider name in ctx.providers |
SMTP (optional)
Omit the smtp field to disable sending. When provided:
| Option | Default | Description |
|--------|---------|-------------|
| smtp.host | — | SMTP server hostname |
| smtp.port | 587 | SMTP port |
| smtp.user | IMAP user | SMTP username (if different) |
| smtp.password | IMAP password | SMTP password (if different) |
| smtp.secure | false | Use implicit TLS (vs STARTTLS) |
Common Provider Configs
Gmail (requires App Password):
createMailProvider({
host: 'imap.gmail.com',
user: '[email protected]',
password: process.env.GMAIL_APP_PASSWORD!,
smtp: { host: 'smtp.gmail.com' },
})iCloud Mail (requires App-Specific Password):
createMailProvider({
host: 'imap.mail.me.com',
user: '[email protected]',
password: process.env.ICLOUD_APP_PASSWORD!,
smtp: { host: 'smtp.mail.me.com', port: 587 },
})Fastmail:
createMailProvider({
host: 'imap.fastmail.com',
user: '[email protected]',
password: process.env.FASTMAIL_APP_PASSWORD!,
smtp: { host: 'smtp.fastmail.com' },
})Self-hosted / Generic IMAP:
createMailProvider({
host: 'mail.example.com',
user: '[email protected]',
password: process.env.MAIL_PASSWORD!,
smtp: { host: 'mail.example.com' },
})Using in Functions
Access the mail client via ctx.providers.mail:
import { defineFunction, z } from 'intentkit';
import type { MailClient } from 'intentkit-mail';
export const checkInbox = defineFunction({
name: 'check_inbox',
intent: 'Check for new unread emails in the inbox',
permissions: ['email:read'],
requires: ['mail'], // Validates provider exists at startup
input: z.object({}),
output: z.object({
unread: z.number(),
messages: z.array(z.object({
from: z.string(),
subject: z.string(),
})),
}),
execute: async (_input, ctx) => {
const mail = ctx.providers.mail as MailClient;
const messages = await mail.listMessages({ unseenOnly: true, limit: 10 });
return {
unread: messages.length,
messages: messages.map(m => ({ from: m.from, subject: m.subject })),
};
},
});Example Functions
The package includes 5 ready-to-use functions in functions/email.ts:
| Function | Intent | Permission |
|----------|--------|------------|
| list_emails | List recent emails in a folder | email:read |
| read_email | Read full email content by UID | email:read |
| search_emails | Search by sender/subject/date/flags | email:read |
| send_email | Send email via SMTP | email:send |
| flag_email | Mark as read/unread/starred | email:update |
Import and register them:
import { listEmails, readEmail, searchEmails, sendEmail, flagEmail } from 'intentkit-mail/functions';
const registry = new IntentRegistry()
.register(listEmails, readEmail, searchEmails, sendEmail, flagEmail);MailClient API
The full client interface for custom function implementations:
interface MailClient {
// Connection
ping(): Promise<boolean>;
disconnect(): Promise<void>;
// Mailboxes
listMailboxes(): Promise<Mailbox[]>;
// Messages
listMessages(options?: ListOptions): Promise<MessageSummary[]>;
getMessage(uid: number, options?: GetMessageOptions): Promise<FullMessage>;
// Search
search(query: SearchQuery): Promise<number[]>;
// Flags
addFlags(uid: number, flags: string[], folder?: string): Promise<void>;
removeFlags(uid: number, flags: string[], folder?: string): Promise<void>;
// Move/Delete
moveMessage(uid: number, from: string, to: string): Promise<void>;
deleteMessage(uid: number, folder?: string): Promise<void>;
// Send
send(options: SendOptions): Promise<{ messageId: string }>;
}Claude Desktop Config
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"mail": {
"command": "node",
"args": ["path/to/your/serve.js"],
"env": {
"GMAIL_APP_PASSWORD": "your-app-password"
}
}
}
}Architecture
Claude (Dispatch / Desktop)
↓ MCP tool call
IntentKit (serve + permissions + hooks)
↓ ctx.providers.mail
intentkit-mail (MailClientImpl)
↓ ↓
imapflow nodemailer
(IMAP) (SMTP)
↓ ↓
Mail Server Mail ServerThe IMAP connection is created once at server startup and kept alive. healthCheck() sends a NOOP command. The connection is cleanly closed on shutdown via IntentKit's lifecycle manager.
License
MIT
