@littlebearapps/outlook-assistant 3.3.0
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 +22 -0
- package/LICENSE +21 -0
- package/README.md +422 -0
- package/advanced/index.js +652 -0
- package/auth/index.js +32 -0
- package/auth/oauth-server.js +233 -0
- package/auth/token-manager.js +105 -0
- package/auth/token-storage.js +359 -0
- package/auth/tools.js +159 -0
- package/calendar/accept.js +72 -0
- package/calendar/cancel.js +72 -0
- package/calendar/create.js +115 -0
- package/calendar/decline.js +72 -0
- package/calendar/delete.js +67 -0
- package/calendar/index.js +130 -0
- package/calendar/list.js +108 -0
- package/categories/index.js +955 -0
- package/config.js +95 -0
- package/contacts/index.js +754 -0
- package/email/attachments.js +365 -0
- package/email/conversations.js +666 -0
- package/email/delta.js +210 -0
- package/email/export.js +572 -0
- package/email/folder-utils.js +192 -0
- package/email/headers.js +344 -0
- package/email/index.js +537 -0
- package/email/list.js +136 -0
- package/email/mark-as-read.js +114 -0
- package/email/mime.js +286 -0
- package/email/read.js +161 -0
- package/email/search.js +628 -0
- package/email/send.js +169 -0
- package/folder/create.js +137 -0
- package/folder/delete.js +108 -0
- package/folder/index.js +112 -0
- package/folder/list.js +289 -0
- package/folder/move.js +186 -0
- package/folder/stats.js +322 -0
- package/index.js +162 -0
- package/llms.txt +76 -0
- package/outlook-auth-server.js +384 -0
- package/package.json +97 -0
- package/rules/create.js +273 -0
- package/rules/index.js +276 -0
- package/rules/list.js +216 -0
- package/settings/index.js +678 -0
- package/utils/field-presets.js +311 -0
- package/utils/graph-api.js +268 -0
- package/utils/mock-data.js +154 -0
- package/utils/odata-helpers.js +33 -0
- package/utils/response-formatter.js +457 -0
- package/utils/safety.js +123 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email folder utilities
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cache of folder information to reduce API calls
|
|
8
|
+
* Format: { userId: { folderName: { id, path } } }
|
|
9
|
+
*/
|
|
10
|
+
const _folderCache = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Well-known folder names and their endpoints
|
|
14
|
+
*/
|
|
15
|
+
const WELL_KNOWN_FOLDERS = {
|
|
16
|
+
inbox: 'me/mailFolders/inbox/messages',
|
|
17
|
+
drafts: 'me/mailFolders/drafts/messages',
|
|
18
|
+
sent: 'me/mailFolders/sentItems/messages',
|
|
19
|
+
deleted: 'me/mailFolders/deletedItems/messages',
|
|
20
|
+
junk: 'me/mailFolders/junkemail/messages',
|
|
21
|
+
archive: 'me/mailFolders/archive/messages',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a folder name to its endpoint path
|
|
26
|
+
* @param {string} accessToken - Access token
|
|
27
|
+
* @param {string} folderName - Folder name to resolve
|
|
28
|
+
* @returns {Promise<string>} - Resolved endpoint path
|
|
29
|
+
*/
|
|
30
|
+
async function resolveFolderPath(accessToken, folderName) {
|
|
31
|
+
// Default to inbox if no folder specified
|
|
32
|
+
if (!folderName) {
|
|
33
|
+
return WELL_KNOWN_FOLDERS['inbox'];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Check if it's a well-known folder (case-insensitive)
|
|
37
|
+
const lowerFolderName = folderName.toLowerCase();
|
|
38
|
+
if (WELL_KNOWN_FOLDERS[lowerFolderName]) {
|
|
39
|
+
console.error(`Using well-known folder path for "${folderName}"`);
|
|
40
|
+
return WELL_KNOWN_FOLDERS[lowerFolderName];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// Try to find the folder by name
|
|
45
|
+
const folderId = await getFolderIdByName(accessToken, folderName);
|
|
46
|
+
if (folderId) {
|
|
47
|
+
const path = `me/mailFolders/${folderId}/messages`;
|
|
48
|
+
console.error(`Resolved folder "${folderName}" to path: ${path}`);
|
|
49
|
+
return path;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// If not found, throw error instead of silently falling back
|
|
53
|
+
throw new Error(
|
|
54
|
+
`Folder "${folderName}" not found. Use the folders tool (action=list) to see available folders.`
|
|
55
|
+
);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error.message.includes('not found')) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Error resolving folder "${folderName}": ${error.message}. Use the folders tool (action=list) to see available folders.`,
|
|
62
|
+
{ cause: error }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the ID of a mail folder by its name
|
|
69
|
+
* @param {string} accessToken - Access token
|
|
70
|
+
* @param {string} folderName - Name of the folder to find
|
|
71
|
+
* @returns {Promise<string|null>} - Folder ID or null if not found
|
|
72
|
+
*/
|
|
73
|
+
async function getFolderIdByName(accessToken, folderName) {
|
|
74
|
+
try {
|
|
75
|
+
// First try with exact match filter
|
|
76
|
+
console.error(`Looking for folder with name "${folderName}"`);
|
|
77
|
+
const response = await callGraphAPI(
|
|
78
|
+
accessToken,
|
|
79
|
+
'GET',
|
|
80
|
+
'me/mailFolders',
|
|
81
|
+
null,
|
|
82
|
+
{ $filter: `displayName eq '${folderName}'` }
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (response.value && response.value.length > 0) {
|
|
86
|
+
console.error(
|
|
87
|
+
`Found folder "${folderName}" with ID: ${response.value[0].id}`
|
|
88
|
+
);
|
|
89
|
+
return response.value[0].id;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// If exact match fails, try to get all folders and do a case-insensitive comparison
|
|
93
|
+
console.error(
|
|
94
|
+
`No exact match found for "${folderName}", trying case-insensitive search`
|
|
95
|
+
);
|
|
96
|
+
const allFoldersResponse = await callGraphAPI(
|
|
97
|
+
accessToken,
|
|
98
|
+
'GET',
|
|
99
|
+
'me/mailFolders',
|
|
100
|
+
null,
|
|
101
|
+
{ $top: 100 }
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (allFoldersResponse.value) {
|
|
105
|
+
const lowerFolderName = folderName.toLowerCase();
|
|
106
|
+
const matchingFolder = allFoldersResponse.value.find(
|
|
107
|
+
(folder) => folder.displayName.toLowerCase() === lowerFolderName
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (matchingFolder) {
|
|
111
|
+
console.error(
|
|
112
|
+
`Found case-insensitive match for "${folderName}" with ID: ${matchingFolder.id}`
|
|
113
|
+
);
|
|
114
|
+
return matchingFolder.id;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.error(`No folder found matching "${folderName}"`);
|
|
119
|
+
return null;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`Error finding folder "${folderName}": ${error.message}`);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get all mail folders
|
|
128
|
+
* @param {string} accessToken - Access token
|
|
129
|
+
* @returns {Promise<Array>} - Array of folder objects
|
|
130
|
+
*/
|
|
131
|
+
async function getAllFolders(accessToken) {
|
|
132
|
+
try {
|
|
133
|
+
// Get top-level folders
|
|
134
|
+
const response = await callGraphAPI(
|
|
135
|
+
accessToken,
|
|
136
|
+
'GET',
|
|
137
|
+
'me/mailFolders',
|
|
138
|
+
null,
|
|
139
|
+
{
|
|
140
|
+
$top: 100,
|
|
141
|
+
$select:
|
|
142
|
+
'id,displayName,parentFolderId,childFolderCount,totalItemCount,unreadItemCount',
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (!response.value) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Get child folders for folders with children
|
|
151
|
+
const foldersWithChildren = response.value.filter(
|
|
152
|
+
(f) => f.childFolderCount > 0
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const childFolderPromises = foldersWithChildren.map(async (folder) => {
|
|
156
|
+
try {
|
|
157
|
+
const childResponse = await callGraphAPI(
|
|
158
|
+
accessToken,
|
|
159
|
+
'GET',
|
|
160
|
+
`me/mailFolders/${folder.id}/childFolders`,
|
|
161
|
+
null,
|
|
162
|
+
{
|
|
163
|
+
$select:
|
|
164
|
+
'id,displayName,parentFolderId,childFolderCount,totalItemCount,unreadItemCount',
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return childResponse.value || [];
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(
|
|
171
|
+
`Error getting child folders for "${folder.displayName}": ${error.message}`
|
|
172
|
+
);
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const childFolders = await Promise.all(childFolderPromises);
|
|
178
|
+
|
|
179
|
+
// Combine top-level folders and all child folders
|
|
180
|
+
return [...response.value, ...childFolders.flat()];
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(`Error getting all folders: ${error.message}`);
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
module.exports = {
|
|
188
|
+
WELL_KNOWN_FOLDERS,
|
|
189
|
+
resolveFolderPath,
|
|
190
|
+
getFolderIdByName,
|
|
191
|
+
getAllFolders,
|
|
192
|
+
};
|
package/email/headers.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email headers functionality
|
|
3
|
+
*
|
|
4
|
+
* Retrieves email headers for forensics, spam analysis, delivery troubleshooting,
|
|
5
|
+
* and threading reconstruction.
|
|
6
|
+
*/
|
|
7
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
8
|
+
const { ensureAuthenticated } = require('../auth');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Important headers to highlight (in order of relevance)
|
|
12
|
+
*/
|
|
13
|
+
const IMPORTANT_HEADERS = [
|
|
14
|
+
// Threading headers
|
|
15
|
+
'Message-ID',
|
|
16
|
+
'In-Reply-To',
|
|
17
|
+
'References',
|
|
18
|
+
// Authentication headers
|
|
19
|
+
'Authentication-Results',
|
|
20
|
+
'DKIM-Signature',
|
|
21
|
+
'ARC-Authentication-Results',
|
|
22
|
+
// Delivery chain
|
|
23
|
+
'Received',
|
|
24
|
+
'Received-SPF',
|
|
25
|
+
// Spam/filtering
|
|
26
|
+
'X-MS-Exchange-Organization-SCL',
|
|
27
|
+
'X-MS-Exchange-Organization-AuthSource',
|
|
28
|
+
'X-Forefront-Antispam-Report',
|
|
29
|
+
'X-Microsoft-Antispam',
|
|
30
|
+
// Content
|
|
31
|
+
'Content-Type',
|
|
32
|
+
'MIME-Version',
|
|
33
|
+
// Custom headers
|
|
34
|
+
'X-Mailer',
|
|
35
|
+
'X-Originating-IP',
|
|
36
|
+
'X-Priority',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Format headers as Markdown
|
|
41
|
+
* @param {Array} headers - Array of {name, value} header objects
|
|
42
|
+
* @param {object} options - Formatting options
|
|
43
|
+
* @returns {string} - Markdown formatted headers
|
|
44
|
+
*/
|
|
45
|
+
function formatHeaders(headers, options = {}) {
|
|
46
|
+
const { groupByType = false, includeAll = true } = options;
|
|
47
|
+
|
|
48
|
+
if (!headers || headers.length === 0) {
|
|
49
|
+
return '*No headers available*';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let output = [];
|
|
53
|
+
|
|
54
|
+
if (groupByType) {
|
|
55
|
+
// Group headers by category
|
|
56
|
+
const groups = {
|
|
57
|
+
Threading: [],
|
|
58
|
+
Authentication: [],
|
|
59
|
+
Delivery: [],
|
|
60
|
+
'Spam/Security': [],
|
|
61
|
+
Content: [],
|
|
62
|
+
Other: [],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
headers.forEach((h) => {
|
|
66
|
+
const name = h.name;
|
|
67
|
+
if (['Message-ID', 'In-Reply-To', 'References'].includes(name)) {
|
|
68
|
+
groups['Threading'].push(h);
|
|
69
|
+
} else if (
|
|
70
|
+
[
|
|
71
|
+
'Authentication-Results',
|
|
72
|
+
'DKIM-Signature',
|
|
73
|
+
'ARC-Authentication-Results',
|
|
74
|
+
'Received-SPF',
|
|
75
|
+
].includes(name)
|
|
76
|
+
) {
|
|
77
|
+
groups['Authentication'].push(h);
|
|
78
|
+
} else if (name === 'Received' || name.startsWith('X-MS-Exchange')) {
|
|
79
|
+
groups['Delivery'].push(h);
|
|
80
|
+
} else if (
|
|
81
|
+
name.includes('Antispam') ||
|
|
82
|
+
name.includes('SCL') ||
|
|
83
|
+
name === 'X-Spam-Status'
|
|
84
|
+
) {
|
|
85
|
+
groups['Spam/Security'].push(h);
|
|
86
|
+
} else if (
|
|
87
|
+
['Content-Type', 'MIME-Version', 'Content-Transfer-Encoding'].includes(
|
|
88
|
+
name
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
groups['Content'].push(h);
|
|
92
|
+
} else {
|
|
93
|
+
groups['Other'].push(h);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
for (const [groupName, groupHeaders] of Object.entries(groups)) {
|
|
98
|
+
if (groupHeaders.length > 0) {
|
|
99
|
+
output.push(`\n### ${groupName}`);
|
|
100
|
+
groupHeaders.forEach((h) => {
|
|
101
|
+
// Truncate very long values
|
|
102
|
+
const value =
|
|
103
|
+
h.value.length > 500 ? h.value.substring(0, 500) + '...' : h.value;
|
|
104
|
+
output.push(`**${h.name}**: \`${value}\``);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// Simple list format
|
|
110
|
+
const importantSet = new Set(IMPORTANT_HEADERS);
|
|
111
|
+
const importantHeaders = [];
|
|
112
|
+
const otherHeaders = [];
|
|
113
|
+
|
|
114
|
+
headers.forEach((h) => {
|
|
115
|
+
if (importantSet.has(h.name)) {
|
|
116
|
+
importantHeaders.push(h);
|
|
117
|
+
} else {
|
|
118
|
+
otherHeaders.push(h);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (importantHeaders.length > 0) {
|
|
123
|
+
output.push('## Key Headers\n');
|
|
124
|
+
importantHeaders.forEach((h) => {
|
|
125
|
+
const value =
|
|
126
|
+
h.value.length > 300 ? h.value.substring(0, 300) + '...' : h.value;
|
|
127
|
+
output.push(`**${h.name}**:`);
|
|
128
|
+
output.push('```');
|
|
129
|
+
output.push(value);
|
|
130
|
+
output.push('```\n');
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (includeAll && otherHeaders.length > 0) {
|
|
135
|
+
output.push('\n## All Other Headers\n');
|
|
136
|
+
otherHeaders.forEach((h) => {
|
|
137
|
+
const value =
|
|
138
|
+
h.value.length > 200 ? h.value.substring(0, 200) + '...' : h.value;
|
|
139
|
+
output.push(`- **${h.name}**: \`${value}\``);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return output.join('\n');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get email headers handler
|
|
149
|
+
* @param {object} args - Tool arguments
|
|
150
|
+
* @param {string} args.id - Email ID (required)
|
|
151
|
+
* @param {boolean} [args.groupByType] - Group headers by category (default: false)
|
|
152
|
+
* @param {boolean} [args.importantOnly] - Show only important headers (default: false)
|
|
153
|
+
* @param {boolean} [args.raw] - Return raw JSON instead of formatted (default: false)
|
|
154
|
+
* @returns {object} - MCP response with headers
|
|
155
|
+
*/
|
|
156
|
+
async function handleGetEmailHeaders(args) {
|
|
157
|
+
const emailId = args.id;
|
|
158
|
+
const groupByType = args.groupByType || false;
|
|
159
|
+
const importantOnly = args.importantOnly || false;
|
|
160
|
+
const raw = args.raw || false;
|
|
161
|
+
|
|
162
|
+
if (!emailId) {
|
|
163
|
+
return {
|
|
164
|
+
content: [
|
|
165
|
+
{
|
|
166
|
+
type: 'text',
|
|
167
|
+
text: 'Email ID is required.',
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Get access token
|
|
175
|
+
const accessToken = await ensureAuthenticated();
|
|
176
|
+
|
|
177
|
+
// Request headers plus threading metadata
|
|
178
|
+
const selectFields = [
|
|
179
|
+
'id',
|
|
180
|
+
'subject',
|
|
181
|
+
'from',
|
|
182
|
+
'internetMessageHeaders',
|
|
183
|
+
'internetMessageId',
|
|
184
|
+
'conversationId',
|
|
185
|
+
'conversationIndex',
|
|
186
|
+
'receivedDateTime',
|
|
187
|
+
'sentDateTime',
|
|
188
|
+
].join(',');
|
|
189
|
+
|
|
190
|
+
const endpoint = `me/messages/${emailId}`;
|
|
191
|
+
const queryParams = {
|
|
192
|
+
$select: selectFields,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const email = await callGraphAPI(
|
|
197
|
+
accessToken,
|
|
198
|
+
'GET',
|
|
199
|
+
endpoint,
|
|
200
|
+
null,
|
|
201
|
+
queryParams
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (!email) {
|
|
205
|
+
return {
|
|
206
|
+
content: [
|
|
207
|
+
{
|
|
208
|
+
type: 'text',
|
|
209
|
+
text: `Email with ID ${emailId} not found.`,
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const headers = email.internetMessageHeaders || [];
|
|
216
|
+
|
|
217
|
+
// Filter to important headers if requested
|
|
218
|
+
let filteredHeaders = headers;
|
|
219
|
+
if (importantOnly) {
|
|
220
|
+
const importantSet = new Set(IMPORTANT_HEADERS);
|
|
221
|
+
filteredHeaders = headers.filter((h) => importantSet.has(h.name));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Return raw JSON if requested
|
|
225
|
+
if (raw) {
|
|
226
|
+
return {
|
|
227
|
+
content: [
|
|
228
|
+
{
|
|
229
|
+
type: 'text',
|
|
230
|
+
text: JSON.stringify(
|
|
231
|
+
{
|
|
232
|
+
id: email.id,
|
|
233
|
+
subject: email.subject,
|
|
234
|
+
internetMessageId: email.internetMessageId,
|
|
235
|
+
conversationId: email.conversationId,
|
|
236
|
+
headers: filteredHeaders,
|
|
237
|
+
},
|
|
238
|
+
null,
|
|
239
|
+
2
|
|
240
|
+
),
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
_meta: {
|
|
244
|
+
emailId: email.id,
|
|
245
|
+
headerCount: filteredHeaders.length,
|
|
246
|
+
format: 'json',
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Build formatted output
|
|
252
|
+
let output = [];
|
|
253
|
+
output.push(`# Email Headers\n`);
|
|
254
|
+
output.push(`**Subject**: ${email.subject || '(no subject)'}`);
|
|
255
|
+
output.push(
|
|
256
|
+
`**From**: ${email.from?.emailAddress?.address || 'unknown'}`
|
|
257
|
+
);
|
|
258
|
+
output.push(`**Received**: ${email.receivedDateTime || 'unknown'}`);
|
|
259
|
+
output.push(
|
|
260
|
+
`**Message-ID**: \`${email.internetMessageId || 'not available'}\``
|
|
261
|
+
);
|
|
262
|
+
output.push(
|
|
263
|
+
`**Conversation-ID**: \`${email.conversationId || 'not available'}\``
|
|
264
|
+
);
|
|
265
|
+
output.push(`\n---\n`);
|
|
266
|
+
output.push(`**Total Headers**: ${headers.length}`);
|
|
267
|
+
if (importantOnly) {
|
|
268
|
+
output.push(` (showing ${filteredHeaders.length} important headers)`);
|
|
269
|
+
}
|
|
270
|
+
output.push('\n');
|
|
271
|
+
|
|
272
|
+
output.push(
|
|
273
|
+
formatHeaders(filteredHeaders, {
|
|
274
|
+
groupByType: groupByType,
|
|
275
|
+
includeAll: !importantOnly,
|
|
276
|
+
})
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
content: [
|
|
281
|
+
{
|
|
282
|
+
type: 'text',
|
|
283
|
+
text: output.join('\n'),
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
_meta: {
|
|
287
|
+
emailId: email.id,
|
|
288
|
+
internetMessageId: email.internetMessageId,
|
|
289
|
+
conversationId: email.conversationId,
|
|
290
|
+
headerCount: headers.length,
|
|
291
|
+
displayedHeaders: filteredHeaders.length,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error(`Error getting email headers: ${error.message}`);
|
|
296
|
+
|
|
297
|
+
if (error.message.includes("doesn't belong to the targeted mailbox")) {
|
|
298
|
+
return {
|
|
299
|
+
content: [
|
|
300
|
+
{
|
|
301
|
+
type: 'text',
|
|
302
|
+
text: `The email ID seems invalid or doesn't belong to your mailbox.`,
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
content: [
|
|
310
|
+
{
|
|
311
|
+
type: 'text',
|
|
312
|
+
text: `Failed to get email headers: ${error.message}`,
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (error.message === 'Authentication required') {
|
|
319
|
+
return {
|
|
320
|
+
content: [
|
|
321
|
+
{
|
|
322
|
+
type: 'text',
|
|
323
|
+
text: "Authentication required. Please use the 'authenticate' tool first.",
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
content: [
|
|
331
|
+
{
|
|
332
|
+
type: 'text',
|
|
333
|
+
text: `Error accessing email: ${error.message}`,
|
|
334
|
+
},
|
|
335
|
+
],
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
module.exports = {
|
|
341
|
+
handleGetEmailHeaders,
|
|
342
|
+
formatHeaders,
|
|
343
|
+
IMPORTANT_HEADERS,
|
|
344
|
+
};
|