Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,43 @@ max_connections = 1
max_messages = 100
```

#### AgentMail (alternative provider)

[AgentMail](https://agentmail.to) can be used as an alternative to IMAP/SMTP for users who want simpler setup. Instead of configuring mail server hosts, ports, and credentials, you just need an API key. AgentMail inboxes can be created programmatically and provide features like `extracted_text` that automatically strips quoted reply chains — useful for AI processing.

Add to your `config.toml`:

```toml
[agentmail]
api_key = "your-agentmail-api-key"
```

Or set the `AGENTMAIL_API_KEY` environment variable:

```json
{
"mcpServers": {
"email": {
"command": "npx",
"args": ["-y", "@codefuturist/email-mcp", "stdio"],
"env": {
"AGENTMAIL_API_KEY": "your-agentmail-api-key"
}
}
}
}
```

When configured, the following additional tools become available:

- `agentmail_create_inbox` — Create a new inbox with a unique `@agentmail.to` address
- `agentmail_list_inboxes` — List all inboxes for the API key
- `agentmail_list_messages` — List messages in an inbox
- `agentmail_get_message` — Get full message content (with auto-stripped reply chains)
- `agentmail_send_message` — Send email from an AgentMail inbox

> **Note:** AgentMail tools are additive — all existing IMAP/SMTP tools continue to work alongside them. You can use both providers simultaneously.

#### Environment Variables

For single-account setups (overrides config file):
Expand All @@ -441,6 +478,7 @@ For single-account setups (overrides config file):
| `MCP_EMAIL_SMTP_POOL_MAX_CONNECTIONS` | `1` | Max pooled SMTP connections |
| `MCP_EMAIL_SMTP_POOL_MAX_MESSAGES` | `100` | Max messages per pooled connection |
| `MCP_EMAIL_RATE_LIMIT` | `10` | Max sends per minute |
| `AGENTMAIL_API_KEY` | — | AgentMail API key (alternative to config file) |

### Email Scheduling

Expand Down
10 changes: 10 additions & 0 deletions src/config/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ function normalizeHookRule(raw: {

function normalizeConfig(raw: RawAppConfig): AppConfig {
return {
agentmail: raw.agentmail ? { apiKey: raw.agentmail.api_key } : undefined,
settings: {
rateLimit: raw.settings.rate_limit,
readOnly: raw.settings.read_only,
Expand Down Expand Up @@ -281,6 +282,7 @@ export async function loadConfig(configPath?: string): Promise<AppConfig> {
throw new Error(
`No configuration found.\n\n` +
`Set environment variables (MCP_EMAIL_ADDRESS, MCP_EMAIL_PASSWORD, etc.)\n` +
`or set AGENTMAIL_API_KEY for AgentMail,\n` +
`or create a config file at: ${configPath ?? CONFIG_FILE}\n\n` +
`Run 'email-mcp setup' for interactive configuration.`,
);
Expand Down Expand Up @@ -310,6 +312,14 @@ export function generateTemplate(): string {
rate_limit = 10 # max emails per minute per account
read_only = false # set to true to disable all write operations

# --- AgentMail (optional, alternative to IMAP/SMTP) ---
# Uncomment to enable AgentMail as an email provider.
# No IMAP/SMTP server configuration needed — just an API key.
# Get your API key at https://agentmail.to
#
# [agentmail]
# api_key = "your-agentmail-api-key"

# [settings.watcher]
# enabled = false # enable IMAP IDLE real-time monitoring
# folders = ["INBOX"] # folders to watch per account
Expand Down
12 changes: 10 additions & 2 deletions src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,12 @@ export const SettingsSchema = z.object({
}),
});

export const AgentMailConfigSchema = z.object({
api_key: z.string().min(1, 'AgentMail API key is required'),
});

export const AppConfigFileSchema = z.object({
agentmail: AgentMailConfigSchema.optional(),
settings: SettingsSchema.default({
rate_limit: 10,
read_only: false,
Expand Down Expand Up @@ -173,8 +178,11 @@ export const AppConfigFileSchema = z.object({
calendar_confirm: true,
},
}),
accounts: z.array(AccountConfigSchema).min(1, 'At least one account is required'),
});
accounts: z.array(AccountConfigSchema).default([]),
})
.refine((data) => data.accounts.length > 0 || data.agentmail != null, {
message: 'At least one IMAP/SMTP account or an [agentmail] section is required',
});

export type RawAccountConfig = z.infer<typeof AccountConfigSchema>;
export type RawAppConfig = z.infer<typeof AppConfigFileSchema>;
11 changes: 11 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import registerAllPrompts from './prompts/register.js';
import registerAllResources from './resources/register.js';
import RateLimiter from './safety/rate-limiter.js';
import createServer, { PKG_VERSION } from './server.js';
import AgentMailService from './services/agentmail.service.js';
import CalendarService from './services/calendar.service.js';
import HooksService from './services/hooks.service.js';
import ImapService from './services/imap.service.js';
Expand Down Expand Up @@ -96,6 +97,10 @@ async function runServer(): Promise<void> {
const watcherService = new WatcherService(config.settings.watcher, config.accounts);
const hooksService = new HooksService(config.settings.hooks, imapService);

// AgentMail (optional — only when [agentmail] section or AGENTMAIL_API_KEY env var is set)
const agentMailApiKey = config.agentmail?.apiKey ?? process.env.AGENTMAIL_API_KEY;
const agentMailService = agentMailApiKey ? new AgentMailService(agentMailApiKey) : undefined;

const server = createServer();
bindServer(server);

Expand All @@ -112,6 +117,7 @@ async function runServer(): Promise<void> {
schedulerService,
watcherService,
hooksService,
agentMailService,
);
registerAllResources(server, connections, imapService, templateService, schedulerService);
registerAllPrompts(server);
Expand Down Expand Up @@ -210,6 +216,10 @@ async function runHttpServer(port: number): Promise<void> {
const watcherService = new WatcherService(config.settings.watcher, config.accounts);
const hooksService = new HooksService(config.settings.hooks, imapService);

// AgentMail (optional)
const agentMailApiKey = config.agentmail?.apiKey ?? process.env.AGENTMAIL_API_KEY;
const agentMailService = agentMailApiKey ? new AgentMailService(agentMailApiKey) : undefined;

// Per-session factory: tools share service instances but each MCP session
// needs its own McpServer because the SDK binds one transport per server.
function buildMcpSession() {
Expand All @@ -228,6 +238,7 @@ async function runHttpServer(port: number): Promise<void> {
schedulerService,
watcherService,
hooksService,
agentMailService,
);
registerAllResources(server, connections, imapService, templateService, schedulerService);
registerAllPrompts(server);
Expand Down
Loading