email-smtp-imap-mcp 2.0.1 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -9,6 +9,8 @@ EMAIL_ACCOUNTS_JSON='{
9
9
  "smtp_secure": false,
10
10
  "smtp_user": "your-email@icloud.com",
11
11
  "smtp_pass": "your-app-specific-password",
12
+ "imap_user": "your-email@icloud.com",
13
+ "imap_pass": "your-app-specific-password",
12
14
  "imap_host": "imap.mail.me.com",
13
15
  "imap_port": 993,
14
16
  "imap_secure": true,
@@ -20,6 +22,8 @@ EMAIL_ACCOUNTS_JSON='{
20
22
  "smtp_secure": false,
21
23
  "smtp_user": "your-email@gmail.com",
22
24
  "smtp_pass": "your-app-specific-password",
25
+ "imap_user": "your-email@gmail.com",
26
+ "imap_pass": "your-app-specific-password",
23
27
  "imap_host": "imap.gmail.com",
24
28
  "imap_port": 993,
25
29
  "imap_secure": true,
@@ -37,9 +41,15 @@ DEFAULT_EMAIL_ACCOUNT="work"
37
41
  # SMTP_SECURE=false
38
42
  # SMTP_USER="your-email@icloud.com"
39
43
  # SMTP_PASS="your-app-specific-password"
44
+ # SMTP_USERNAME="your-email@icloud.com" # Alias for SMTP_USER
45
+ # SMTP_PASSWORD="your-app-specific-password" # Alias for SMTP_PASS
40
46
  # IMAP_HOST="imap.mail.me.com"
41
47
  # IMAP_PORT=993
42
48
  # IMAP_SECURE=true
49
+ # IMAP_USER="your-email@icloud.com"
50
+ # IMAP_PASS="your-app-specific-password"
51
+ # IMAP_USERNAME="your-email@icloud.com" # Alias for IMAP_USER
52
+ # IMAP_PASSWORD="your-app-specific-password" # Alias for IMAP_PASS
43
53
  # DEFAULT_FROM_NAME="Your Name"
44
54
 
45
55
  # ===== NOTES =====
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sami Halawa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,35 +1,36 @@
1
1
  # Email MCP Server
2
2
 
3
- A clean, simple MCP server for email operations (SMTP + IMAP).
3
+ A clean, simple stdio MCP server for email operations supporting both SMTP (sending) and IMAP (reading).
4
+
5
+ [![npm version](https://badge.fury.io/js/email-smtp-imap-mcp.svg)](https://www.npmjs.com/package/email-smtp-imap-mcp)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
7
 
5
8
  ## Features
6
9
 
7
- - ✅ **Send emails** (HTML + attachments)
8
- - ✅ **Search emails** (flexible filters)
9
- - ✅ **Reply/Forward** (with threading)
10
+ - ✅ **Send emails** with HTML and attachments
11
+ - ✅ **Search emails** with flexible filters
12
+ - ✅ **Reply/Forward** with proper threading
10
13
  - ✅ **Organize** (mark read, archive, flag)
11
- - ✅ **List folders**
14
+ - ✅ **Multi-account support** for managing multiple email accounts
15
+ - ✅ **List folders** to browse your mailbox structure
12
16
 
13
- ## Installation
17
+ ## Quick Start
14
18
 
15
- ### Option 1: NPM (Recommended)
19
+ ### Installation
16
20
 
17
21
  ```bash
18
- npm install -g email-smtp-imap-mcp
22
+ npx -y email-smtp-imap-mcp
19
23
  ```
20
24
 
21
- ### Option 2: From Source
25
+ Or install globally:
22
26
 
23
27
  ```bash
24
- git clone https://github.com/samihalawa/email-smtp-imap-mcp.git
25
- cd email-smtp-imap-mcp
26
- npm install
27
- npm run build
28
+ npm install -g email-smtp-imap-mcp
28
29
  ```
29
30
 
30
- ## Configuration
31
+ ### Configuration
31
32
 
32
- Add to your `claude_desktop_config.json`:
33
+ Add to your Claude Desktop config file:
33
34
 
34
35
  **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
35
36
  **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
@@ -41,76 +42,118 @@ Add to your `claude_desktop_config.json`:
41
42
  "command": "npx",
42
43
  "args": ["-y", "email-smtp-imap-mcp"],
43
44
  "env": {
44
- "EMAIL_ACCOUNTS_JSON": "{\"icloud\":{\"smtp\":{\"host\":\"smtp.mail.me.com\",\"port\":587,\"user\":\"your@icloud.com\",\"password\":\"your-app-password\"},\"imap\":{\"host\":\"imap.mail.me.com\",\"port\":993},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@icloud.com\",\"alias@domain.com\"]}}",
45
- "DEFAULT_EMAIL_ACCOUNT": "icloud"
45
+ "EMAIL_ACCOUNTS_JSON": "{\"work\":{\"smtp\":{\"host\":\"smtp.gmail.com\",\"port\":587,\"user\":\"your@gmail.com\",\"password\":\"app-password\"},\"imap\":{\"host\":\"imap.gmail.com\",\"port\":993,\"user\":\"your@gmail.com\",\"password\":\"app-password\"},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@gmail.com\"]}}",
46
+ "DEFAULT_EMAIL_ACCOUNT": "work"
46
47
  }
47
48
  }
48
49
  }
49
50
  }
50
51
  ```
51
52
 
52
- **Replace** `your@icloud.com`, `your-app-password`, and `Your Name` with your actual credentials.
53
+ **⚠️ Important**: Restart Claude Desktop after adding this configuration.
53
54
 
54
- ### Email Provider Settings
55
-
56
- <details>
57
- <summary>📧 iCloud Mail</summary>
55
+ ## Email Provider Settings
58
56
 
57
+ ### Gmail
59
58
  ```json
60
- "EMAIL_ACCOUNTS_JSON": "{\"icloud\":{\"smtp\":{\"host\":\"smtp.mail.me.com\",\"port\":587,\"user\":\"your@icloud.com\",\"password\":\"app-specific-password\"},\"imap\":{\"host\":\"imap.mail.me.com\",\"port\":993},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@icloud.com\"]}}"
59
+ "EMAIL_ACCOUNTS_JSON": "{\"gmail\":{\"smtp\":{\"host\":\"smtp.gmail.com\",\"port\":587,\"user\":\"your@gmail.com\",\"password\":\"app-password\"},\"imap\":{\"host\":\"imap.gmail.com\",\"port\":993,\"user\":\"your@gmail.com\",\"password\":\"app-password\"},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@gmail.com\"]}}"
61
60
  ```
61
+ **Setup**: [Create App Password](https://support.google.com/accounts/answer/185833)
62
62
 
63
- **Note**: Use [app-specific password](https://support.apple.com/en-us/102654), not your iCloud password.
64
- </details>
63
+ ### iCloud Mail
64
+ ```json
65
+ "EMAIL_ACCOUNTS_JSON": "{\"icloud\":{\"smtp\":{\"host\":\"smtp.mail.me.com\",\"port\":587,\"user\":\"your@icloud.com\",\"password\":\"app-specific-password\"},\"imap\":{\"host\":\"imap.mail.me.com\",\"port\":993,\"user\":\"your@icloud.com\",\"password\":\"app-specific-password\"},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@icloud.com\"]}}"
66
+ ```
67
+ **Setup**: [Generate App-Specific Password](https://support.apple.com/en-us/102654)
65
68
 
66
- <details>
67
- <summary>📧 Gmail</summary>
69
+ ### Outlook/Office 365
70
+ ```json
71
+ "EMAIL_ACCOUNTS_JSON": "{\"outlook\":{\"smtp\":{\"host\":\"smtp-mail.outlook.com\",\"port\":587,\"user\":\"your@outlook.com\",\"password\":\"your-password\"},\"imap\":{\"host\":\"outlook.office365.com\",\"port\":993,\"user\":\"your@outlook.com\",\"password\":\"your-password\"},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@outlook.com\"]}}"
72
+ ```
68
73
 
74
+ ### Multiple Accounts
69
75
  ```json
70
- "EMAIL_ACCOUNTS_JSON": "{\"gmail\":{\"smtp\":{\"host\":\"smtp.gmail.com\",\"port\":587,\"user\":\"your@gmail.com\",\"password\":\"app-password\"},\"imap\":{\"host\":\"imap.gmail.com\",\"port\":993},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@gmail.com\"]}}"
76
+ "EMAIL_ACCOUNTS_JSON": "{\"work\":{\"smtp\":{\"host\":\"smtp.gmail.com\",\"port\":587,\"user\":\"work@company.com\",\"password\":\"app-password\"},\"imap\":{\"host\":\"imap.gmail.com\",\"port\":993,\"user\":\"work@company.com\",\"password\":\"app-password\"},\"default_from_name\":\"John Doe\"},\"personal\":{\"smtp\":{\"host\":\"smtp.mail.me.com\",\"port\":587,\"user\":\"me@icloud.com\",\"password\":\"app-password\"},\"imap\":{\"host\":\"imap.mail.me.com\",\"port\":993,\"user\":\"me@icloud.com\",\"password\":\"app-password\"},\"default_from_name\":\"John\"}}",
77
+ "DEFAULT_EMAIL_ACCOUNT": "work"
71
78
  ```
72
79
 
73
- **Note**: Use [app password](https://support.google.com/accounts/answer/185833), not your Google password.
74
- </details>
80
+ The server also accepts flat or single-account environment variables. For compatibility, `SMTP_USERNAME`/`SMTP_PASSWORD` are aliases for `SMTP_USER`/`SMTP_PASS`, `IMAP_USERNAME`/`IMAP_PASSWORD` are aliases for `IMAP_USER`/`IMAP_PASS`, and `IMAP_USER`/`IMAP_PASS` fall back to the SMTP credentials when omitted.
75
81
 
76
- <details>
77
- <summary>📧 Outlook/Office 365</summary>
82
+ ## Available Tools
78
83
 
79
- ```json
80
- "EMAIL_ACCOUNTS_JSON": "{\"outlook\":{\"smtp\":{\"host\":\"smtp-mail.outlook.com\",\"port\":587,\"user\":\"your@outlook.com\",\"password\":\"your-password\"},\"imap\":{\"host\":\"outlook.office365.com\",\"port\":993},\"default_from_name\":\"Your Name\",\"sender_emails\":[\"your@outlook.com\"]}}"
81
- ```
82
- </details>
84
+ | Tool | Description |
85
+ |------|-------------|
86
+ | `emails_find` | Search emails with flexible filters (sender, subject, date, attachments, etc.) |
87
+ | `emails_modify` | Mark as read/unread, flag, archive, or move emails |
88
+ | `email_send` | Send new emails with HTML content and attachments |
89
+ | `email_respond` | Reply or forward emails with proper threading |
90
+ | `folders_list` | List all available email folders |
83
91
 
84
- ---
92
+ ## Usage Examples
85
93
 
86
- **⚠️ Important**: Restart Claude Desktop after adding configuration.
94
+ Ask Claude to:
87
95
 
88
- ## 5 Tools
96
+ - "Find unread emails from last week"
97
+ - "Send an email to team@company.com about the meeting"
98
+ - "Reply to the last email from Sarah"
99
+ - "Archive all emails older than 30 days"
100
+ - "List my email folders"
101
+ - "Find emails with attachments from my boss"
102
+ - "Mark all emails from newsletter@site.com as read"
89
103
 
90
- | Tool | Purpose |
91
- |------|---------|
92
- | `emails_find` | Search emails with filters |
93
- | `emails_modify` | Mark read, archive, flag |
94
- | `email_send` | Send new emails |
95
- | `email_respond` | Reply or forward |
96
- | `folders_list` | List folders |
104
+ ## Security Notes
97
105
 
98
- ## Usage Examples
106
+ - **Never commit** `.env` files or credentials to version control
107
+ - Use **app-specific passwords** or **app passwords**, not your main account password
108
+ - The server runs **locally** on your machine - credentials stay private
109
+ - All email connections use **TLS encryption** (ports 587 for SMTP, 993 for IMAP)
99
110
 
100
- ```
101
- "Find unread emails from last week"
102
- "Send an email to team@company.com"
103
- "Reply to the last email from John"
104
- "Archive all emails older than 30 days"
105
- "List my email folders"
111
+ ## Development
112
+
113
+ ```bash
114
+ # Clone the repository
115
+ git clone https://github.com/samihalawa/email-smtp-imap-mcp.git
116
+ cd email-smtp-imap-mcp
117
+
118
+ # Install dependencies
119
+ npm install
120
+
121
+ # Build
122
+ npm run build
123
+
124
+ # Run locally
125
+ npm start
106
126
  ```
107
127
 
108
- ## Documentation
128
+ ## Troubleshooting
109
129
 
110
- - **QUICK_REFERENCE.md** - Command examples
111
- - **DESIGN.md** - Architecture details
112
- - **SETUP_COMPLETE.md** - Full setup guide
130
+ ### Authentication Errors
131
+ - Make sure you're using an **app password**, not your regular password
132
+ - For Gmail: [Create App Password](https://support.google.com/accounts/answer/185833)
133
+ - For iCloud: [Generate App-Specific Password](https://support.apple.com/en-us/102654)
134
+
135
+ ### Server Not Starting
136
+ - Verify your configuration JSON is properly escaped
137
+ - Check that ports 587 (SMTP) and 993 (IMAP) are not blocked by your firewall
138
+ - Restart Claude Desktop after configuration changes
139
+
140
+ ### Connection Issues
141
+ - Confirm your email provider allows IMAP/SMTP access
142
+ - Check your internet connection
143
+ - Verify the SMTP/IMAP host and port settings for your provider
113
144
 
114
145
  ## License
115
146
 
116
- MIT
147
+ MIT License - see [LICENSE](LICENSE) file for details
148
+
149
+ ## Contributing
150
+
151
+ Contributions are welcome! Please feel free to submit a Pull Request.
152
+
153
+ ## Author
154
+
155
+ **Sami Halawa** - [GitHub](https://github.com/samihalawa)
156
+
157
+ ---
158
+
159
+ Made with ❤️ for the MCP community
@@ -1,6 +1,48 @@
1
1
  /**
2
2
  * Email account configuration management
3
3
  */
4
+ function firstDefined(...values) {
5
+ return values.find((value) => value !== undefined && value !== '') || '';
6
+ }
7
+ function parsePort(value, fallback) {
8
+ if (typeof value === 'number')
9
+ return value;
10
+ if (typeof value === 'string' && value.trim() !== '') {
11
+ const parsed = Number.parseInt(value, 10);
12
+ if (!Number.isNaN(parsed))
13
+ return parsed;
14
+ }
15
+ return fallback;
16
+ }
17
+ function toBoolean(value, fallback) {
18
+ if (value === undefined || value === null || value === '')
19
+ return fallback;
20
+ if (typeof value === 'boolean')
21
+ return value;
22
+ return String(value).toLowerCase() === 'true';
23
+ }
24
+ function normalizeAccountConfig(cfg) {
25
+ const smtp = cfg.smtp || {};
26
+ const imap = cfg.imap || {};
27
+ const smtpUser = firstDefined(smtp.user, cfg.smtp_user, cfg.SMTP_USER, cfg.SMTP_USERNAME);
28
+ const smtpPass = firstDefined(smtp.password, smtp.pass, cfg.smtp_pass, cfg.SMTP_PASS, cfg.SMTP_PASSWORD);
29
+ const imapUser = firstDefined(imap.user, imap.username, cfg.imap_user, cfg.IMAP_USER, cfg.IMAP_USERNAME, smtpUser);
30
+ const imapPass = firstDefined(imap.password, imap.pass, cfg.imap_pass, cfg.IMAP_PASS, cfg.IMAP_PASSWORD, smtpPass);
31
+ return {
32
+ smtp_host: firstDefined(smtp.host, cfg.smtp_host, cfg.SMTP_HOST, cfg.SMTP_SERVER, cfg.MTP_SERVER),
33
+ smtp_port: parsePort(smtp.port ?? cfg.smtp_port ?? cfg.SMTP_PORT, 587),
34
+ smtp_secure: toBoolean(smtp.secure ?? cfg.smtp_secure ?? cfg.SMTP_SECURE, parsePort(smtp.port ?? cfg.smtp_port ?? cfg.SMTP_PORT, 587) === 465),
35
+ smtp_user: smtpUser,
36
+ smtp_pass: smtpPass,
37
+ imap_user: imapUser,
38
+ imap_pass: imapPass,
39
+ imap_host: firstDefined(imap.host, cfg.imap_host, cfg.IMAP_HOST, cfg.IMAP_SERVER),
40
+ imap_port: parsePort(imap.port ?? cfg.imap_port ?? cfg.IMAP_PORT, 993),
41
+ imap_secure: toBoolean(imap.secure ?? cfg.imap_secure ?? cfg.IMAP_SECURE, parsePort(imap.port ?? cfg.imap_port ?? cfg.IMAP_PORT, 993) === 993),
42
+ default_from_name: cfg.default_from_name || cfg.DEFAULT_FROM_NAME,
43
+ sender_emails: cfg.sender_emails || cfg.SENDER_EMAILS
44
+ };
45
+ }
4
46
  /**
5
47
  * Load email accounts from environment variables
6
48
  */
@@ -9,7 +51,14 @@ export function loadAccounts() {
9
51
  const jsonConfig = process.env.EMAIL_ACCOUNTS_JSON;
10
52
  if (jsonConfig) {
11
53
  try {
12
- return JSON.parse(jsonConfig);
54
+ const parsed = JSON.parse(jsonConfig);
55
+ // Transform nested structure to flat structure
56
+ const accounts = {};
57
+ for (const [accountName, config] of Object.entries(parsed)) {
58
+ const cfg = config;
59
+ accounts[accountName] = normalizeAccountConfig(cfg);
60
+ }
61
+ return accounts;
13
62
  }
14
63
  catch (error) {
15
64
  throw new Error(`Failed to parse EMAIL_ACCOUNTS_JSON: ${error}`);
@@ -17,19 +66,34 @@ export function loadAccounts() {
17
66
  }
18
67
  // Fall back to single account from individual ENV vars
19
68
  const singleAccount = {
20
- smtp_host: process.env.SMTP_HOST || '',
21
- smtp_port: parseInt(process.env.SMTP_PORT || '587'),
22
- smtp_secure: process.env.SMTP_SECURE === 'true',
23
- smtp_user: process.env.SMTP_USER || '',
24
- smtp_pass: process.env.SMTP_PASS || '',
25
- imap_host: process.env.IMAP_HOST || '',
26
- imap_port: parseInt(process.env.IMAP_PORT || '993'),
27
- imap_secure: process.env.IMAP_SECURE !== 'false', // Default to true
69
+ smtp_host: firstDefined(process.env.SMTP_HOST, process.env.SMTP_SERVER, process.env.MTP_SERVER),
70
+ smtp_port: parsePort(process.env.SMTP_PORT, 587),
71
+ smtp_secure: toBoolean(process.env.SMTP_SECURE, parsePort(process.env.SMTP_PORT, 587) === 465),
72
+ smtp_user: firstDefined(process.env.SMTP_USER, process.env.SMTP_USERNAME),
73
+ smtp_pass: firstDefined(process.env.SMTP_PASS, process.env.SMTP_PASSWORD),
74
+ imap_user: firstDefined(process.env.IMAP_USER, process.env.IMAP_USERNAME, process.env.SMTP_USER, process.env.SMTP_USERNAME),
75
+ imap_pass: firstDefined(process.env.IMAP_PASS, process.env.IMAP_PASSWORD, process.env.SMTP_PASS, process.env.SMTP_PASSWORD),
76
+ imap_host: firstDefined(process.env.IMAP_HOST, process.env.IMAP_SERVER),
77
+ imap_port: parsePort(process.env.IMAP_PORT, 993),
78
+ imap_secure: toBoolean(process.env.IMAP_SECURE, parsePort(process.env.IMAP_PORT, 993) === 993),
28
79
  default_from_name: process.env.DEFAULT_FROM_NAME
29
80
  };
30
81
  // Validate single account has required fields
31
- if (!singleAccount.smtp_host || !singleAccount.smtp_user || !singleAccount.smtp_pass) {
32
- throw new Error('Email account configuration not found. Set EMAIL_ACCOUNTS_JSON or individual SMTP_* variables.');
82
+ const missingFields = [];
83
+ if (!singleAccount.smtp_host)
84
+ missingFields.push('SMTP_HOST');
85
+ if (!singleAccount.smtp_user)
86
+ missingFields.push('SMTP_USER');
87
+ if (!singleAccount.smtp_pass)
88
+ missingFields.push('SMTP_PASS');
89
+ if (!singleAccount.imap_host)
90
+ missingFields.push('IMAP_HOST');
91
+ if (!singleAccount.imap_user)
92
+ missingFields.push('IMAP_USER');
93
+ if (!singleAccount.imap_pass)
94
+ missingFields.push('IMAP_PASS');
95
+ if (missingFields.length > 0) {
96
+ throw new Error(`Missing required email configuration: ${missingFields.join(', ')}. Set EMAIL_ACCOUNTS_JSON or individual environment variables.`);
33
97
  }
34
98
  // Use DEFAULT_EMAIL_ACCOUNT as the account name, or "default"
35
99
  const accountName = process.env.DEFAULT_EMAIL_ACCOUNT || 'default';
@@ -18,6 +18,7 @@ export async function handleEmailsFind(args) {
18
18
  return JSON.stringify({
19
19
  success: true,
20
20
  account: name,
21
+ total_found: emails.length,
21
22
  count: emails.length,
22
23
  emails
23
24
  }, null, 2);