@agenticmail/enterprise 0.5.353 → 0.5.355
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/dist/{agent-heartbeat-DOMJAVCK.js → agent-heartbeat-ZCVMYFMO.js} +1 -1
- package/dist/{agent-tools-KPMEG6GA.js → agent-tools-LOVO4CLJ.js} +47 -1
- package/dist/{chunk-XI6E3OBF.js → chunk-3VZOFEQF.js} +13 -13
- package/dist/{chunk-ZGYVXYQQ.js → chunk-5WDYN4UV.js} +107 -71
- package/dist/{chunk-NOAQG5CY.js → chunk-HIQY73V2.js} +1 -1
- package/dist/{chunk-5IRAWWEJ.js → chunk-PPGBBASR.js} +20 -20
- package/dist/{chunk-6IM6WMM7.js → chunk-RCCWFEZI.js} +5 -5
- package/dist/{chunk-VQHMGRGD.js → chunk-WECNT5FR.js} +2 -2
- package/dist/{cli-agent-AEG2ZSKO.js → cli-agent-SPDASSB7.js} +6 -6
- package/dist/{cli-serve-RNQ3N477.js → cli-serve-JS5CDMOW.js} +1 -1
- package/dist/{cli-validate-Z726VJCN.js → cli-validate-ZO3PW64W.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/dashboard/pages/agent-detail/overview.js +2 -1
- package/dist/index.js +6 -6
- package/dist/{routes-OA6Y74YU.js → routes-S43BQMDK.js} +3 -3
- package/dist/{runtime-ONDAF63W.js → runtime-3GLGCAGF.js} +1 -1
- package/dist/{server-Y7MTUIBX.js → server-5URLZCXN.js} +4 -4
- package/dist/{setup-PLIKKNBE.js → setup-R2ECMQLR.js} +1 -1
- package/dist/{skills-EL4RTJKK.js → skills-4MHEPJGC.js} +2 -2
- package/dist/smtp-email-WGUG4M45.js +332 -0
- package/logs/cloudflared-error.log +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import "./chunk-KFQGP6VL.js";
|
|
2
|
+
|
|
3
|
+
// src/agent-tools/tools/smtp-email.ts
|
|
4
|
+
import { createTransport } from "nodemailer";
|
|
5
|
+
import { ImapFlow } from "imapflow";
|
|
6
|
+
function getSmtpConfig(ctx) {
|
|
7
|
+
const ec = ctx.emailConfig;
|
|
8
|
+
if (!ec?.smtpHost) throw new Error("SMTP not configured. Set up email credentials in agent settings.");
|
|
9
|
+
return {
|
|
10
|
+
host: ec.smtpHost,
|
|
11
|
+
port: ec.smtpPort || 587,
|
|
12
|
+
secure: (ec.smtpPort || 587) === 465,
|
|
13
|
+
auth: { user: ec.smtpUser || ec.email, pass: ec.smtpPass }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function getImapConfig(ctx) {
|
|
17
|
+
const ec = ctx.emailConfig;
|
|
18
|
+
if (!ec?.imapHost && !ec?.smtpHost) throw new Error("IMAP not configured. Set up email credentials in agent settings.");
|
|
19
|
+
const smtpHost = ec.smtpHost || "";
|
|
20
|
+
let imapHost = ec.imapHost;
|
|
21
|
+
if (!imapHost) {
|
|
22
|
+
if (smtpHost.includes("smtp.gmail")) imapHost = "imap.gmail.com";
|
|
23
|
+
else if (smtpHost.includes("smtp.office365") || smtpHost.includes("smtp.outlook")) imapHost = "outlook.office365.com";
|
|
24
|
+
else if (smtpHost.includes("smtp.yahoo")) imapHost = "imap.mail.yahoo.com";
|
|
25
|
+
else imapHost = smtpHost.replace("smtp.", "imap.");
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
host: imapHost,
|
|
29
|
+
port: ec.imapPort || 993,
|
|
30
|
+
secure: true,
|
|
31
|
+
auth: { user: ec.smtpUser || ec.imapUser || ec.email, pass: ec.smtpPass || ec.imapPass },
|
|
32
|
+
logger: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function withImap(ctx, fn) {
|
|
36
|
+
const config = getImapConfig(ctx);
|
|
37
|
+
const client = new ImapFlow(config);
|
|
38
|
+
try {
|
|
39
|
+
await client.connect();
|
|
40
|
+
return await fn(client);
|
|
41
|
+
} finally {
|
|
42
|
+
try {
|
|
43
|
+
await client.logout();
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function formatAddress(addr) {
|
|
49
|
+
if (!addr) return "";
|
|
50
|
+
if (typeof addr === "string") return addr;
|
|
51
|
+
if (addr.name) return `${addr.name} <${addr.address}>`;
|
|
52
|
+
return addr.address || "";
|
|
53
|
+
}
|
|
54
|
+
function formatAddressList(list) {
|
|
55
|
+
if (!list) return "";
|
|
56
|
+
if (Array.isArray(list)) return list.map(formatAddress).join(", ");
|
|
57
|
+
return formatAddress(list);
|
|
58
|
+
}
|
|
59
|
+
async function emailSend(ctx, params) {
|
|
60
|
+
const { to, cc, bcc, subject, body, html, replyTo } = params;
|
|
61
|
+
if (!to) return { error: "Missing required parameter: to" };
|
|
62
|
+
if (!subject && !body) return { error: "Must provide subject or body" };
|
|
63
|
+
const transport = createTransport(getSmtpConfig(ctx));
|
|
64
|
+
const from = ctx.emailConfig?.email || ctx.emailConfig?.smtpUser;
|
|
65
|
+
const info = await transport.sendMail({
|
|
66
|
+
from,
|
|
67
|
+
to,
|
|
68
|
+
cc,
|
|
69
|
+
bcc,
|
|
70
|
+
subject: subject || "(no subject)",
|
|
71
|
+
text: body,
|
|
72
|
+
html,
|
|
73
|
+
replyTo
|
|
74
|
+
});
|
|
75
|
+
return { result: { messageId: info.messageId, to, subject, status: "sent" } };
|
|
76
|
+
}
|
|
77
|
+
async function emailReply(ctx, params) {
|
|
78
|
+
const { uid, folder, body, html, all } = params;
|
|
79
|
+
if (!uid) return { error: "Missing required parameter: uid (email UID to reply to)" };
|
|
80
|
+
const original = await withImap(ctx, async (client) => {
|
|
81
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
82
|
+
try {
|
|
83
|
+
const msg = await client.fetchOne(String(uid), { envelope: true, uid: true });
|
|
84
|
+
return msg?.envelope;
|
|
85
|
+
} finally {
|
|
86
|
+
lock.release();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!original) return { error: `Email UID ${uid} not found` };
|
|
90
|
+
const transport = createTransport(getSmtpConfig(ctx));
|
|
91
|
+
const from = ctx.emailConfig?.email || ctx.emailConfig?.smtpUser;
|
|
92
|
+
const replyTo = all ? [...original.from || [], ...original.to || [], ...original.cc || []].map((a) => a.address).filter((a) => a !== from) : (original.replyTo || original.from || []).map((a) => a.address);
|
|
93
|
+
const info = await transport.sendMail({
|
|
94
|
+
from,
|
|
95
|
+
to: replyTo.join(", "),
|
|
96
|
+
subject: original.subject?.startsWith("Re:") ? original.subject : `Re: ${original.subject || ""}`,
|
|
97
|
+
text: body,
|
|
98
|
+
html,
|
|
99
|
+
inReplyTo: original.messageId,
|
|
100
|
+
references: original.messageId
|
|
101
|
+
});
|
|
102
|
+
return { result: { messageId: info.messageId, to: replyTo, subject: `Re: ${original.subject}`, status: "sent" } };
|
|
103
|
+
}
|
|
104
|
+
async function emailForward(ctx, params) {
|
|
105
|
+
const { uid, to, folder, comment } = params;
|
|
106
|
+
if (!uid || !to) return { error: "Missing required parameters: uid, to" };
|
|
107
|
+
const original = await withImap(ctx, async (client) => {
|
|
108
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
109
|
+
try {
|
|
110
|
+
const msg = await client.fetchOne(String(uid), { envelope: true, source: true, uid: true });
|
|
111
|
+
return msg;
|
|
112
|
+
} finally {
|
|
113
|
+
lock.release();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (!original) return { error: `Email UID ${uid} not found` };
|
|
117
|
+
const transport = createTransport(getSmtpConfig(ctx));
|
|
118
|
+
const from = ctx.emailConfig?.email || ctx.emailConfig?.smtpUser;
|
|
119
|
+
const origSubject = original.envelope?.subject || "";
|
|
120
|
+
const body = comment ? `${comment}
|
|
121
|
+
|
|
122
|
+
---------- Forwarded message ----------
|
|
123
|
+
${original.source?.toString() || "(no content)"}` : `---------- Forwarded message ----------
|
|
124
|
+
${original.source?.toString() || "(no content)"}`;
|
|
125
|
+
const info = await transport.sendMail({
|
|
126
|
+
from,
|
|
127
|
+
to,
|
|
128
|
+
subject: origSubject.startsWith("Fwd:") ? origSubject : `Fwd: ${origSubject}`,
|
|
129
|
+
text: body
|
|
130
|
+
});
|
|
131
|
+
return { result: { messageId: info.messageId, to, subject: `Fwd: ${origSubject}`, status: "forwarded" } };
|
|
132
|
+
}
|
|
133
|
+
async function emailSearch(ctx, params) {
|
|
134
|
+
const { query, from, to, subject, since, before, folder, limit } = params;
|
|
135
|
+
const maxResults = Math.min(limit || 20, 50);
|
|
136
|
+
return withImap(ctx, async (client) => {
|
|
137
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
138
|
+
try {
|
|
139
|
+
const searchQuery = {};
|
|
140
|
+
if (query) searchQuery.body = query;
|
|
141
|
+
if (from) searchQuery.from = from;
|
|
142
|
+
if (to) searchQuery.to = to;
|
|
143
|
+
if (subject) searchQuery.subject = subject;
|
|
144
|
+
if (since) searchQuery.since = new Date(since);
|
|
145
|
+
if (before) searchQuery.before = new Date(before);
|
|
146
|
+
if (Object.keys(searchQuery).length === 0) searchQuery.all = true;
|
|
147
|
+
const uids = await client.search(searchQuery, { uid: true });
|
|
148
|
+
const recentUids = uids.slice(-maxResults).reverse();
|
|
149
|
+
if (recentUids.length === 0) return { result: { messages: [], total: 0 } };
|
|
150
|
+
const messages = [];
|
|
151
|
+
for await (const msg of client.fetch(recentUids.map(String), { envelope: true, uid: true, flags: true })) {
|
|
152
|
+
messages.push({
|
|
153
|
+
uid: msg.uid,
|
|
154
|
+
from: formatAddressList(msg.envelope?.from),
|
|
155
|
+
to: formatAddressList(msg.envelope?.to),
|
|
156
|
+
subject: msg.envelope?.subject || "(no subject)",
|
|
157
|
+
date: msg.envelope?.date?.toISOString(),
|
|
158
|
+
flags: [...msg.flags || []],
|
|
159
|
+
read: msg.flags?.has("\\Seen")
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return { result: { messages, total: uids.length, showing: messages.length } };
|
|
163
|
+
} finally {
|
|
164
|
+
lock.release();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async function emailRead(ctx, params) {
|
|
169
|
+
const { uid, folder, markRead } = params;
|
|
170
|
+
if (!uid) return { error: "Missing required parameter: uid" };
|
|
171
|
+
return withImap(ctx, async (client) => {
|
|
172
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
173
|
+
try {
|
|
174
|
+
const msg = await client.fetchOne(String(uid), {
|
|
175
|
+
envelope: true,
|
|
176
|
+
uid: true,
|
|
177
|
+
flags: true,
|
|
178
|
+
bodyStructure: true,
|
|
179
|
+
source: { maxBytes: 5e5 }
|
|
180
|
+
});
|
|
181
|
+
if (!msg) return { error: `Email UID ${uid} not found` };
|
|
182
|
+
let textBody = "";
|
|
183
|
+
if (msg.source) {
|
|
184
|
+
const raw = msg.source.toString();
|
|
185
|
+
const textMatch = raw.match(/Content-Type: text\/plain[\s\S]*?\r\n\r\n([\s\S]*?)(?:\r\n--|\r\n\.\r\n|$)/i);
|
|
186
|
+
if (textMatch) textBody = textMatch[1].trim();
|
|
187
|
+
else textBody = raw.slice(raw.indexOf("\r\n\r\n") + 4).trim().slice(0, 2e3);
|
|
188
|
+
}
|
|
189
|
+
if (markRead !== false) {
|
|
190
|
+
try {
|
|
191
|
+
await client.messageFlagsAdd(String(uid), ["\\Seen"], { uid: true });
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
result: {
|
|
197
|
+
uid: msg.uid,
|
|
198
|
+
from: formatAddressList(msg.envelope?.from),
|
|
199
|
+
to: formatAddressList(msg.envelope?.to),
|
|
200
|
+
cc: formatAddressList(msg.envelope?.cc),
|
|
201
|
+
subject: msg.envelope?.subject || "(no subject)",
|
|
202
|
+
date: msg.envelope?.date?.toISOString(),
|
|
203
|
+
messageId: msg.envelope?.messageId,
|
|
204
|
+
body: textBody,
|
|
205
|
+
flags: [...msg.flags || []]
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
} finally {
|
|
209
|
+
lock.release();
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function emailList(ctx, params) {
|
|
214
|
+
const { folder, limit, unreadOnly } = params;
|
|
215
|
+
const maxResults = Math.min(limit || 20, 50);
|
|
216
|
+
return withImap(ctx, async (client) => {
|
|
217
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
218
|
+
try {
|
|
219
|
+
const searchQuery = unreadOnly ? { unseen: true } : { all: true };
|
|
220
|
+
const uids = await client.search(searchQuery, { uid: true });
|
|
221
|
+
const recentUids = uids.slice(-maxResults).reverse();
|
|
222
|
+
if (recentUids.length === 0) return { result: { messages: [], total: 0 } };
|
|
223
|
+
const messages = [];
|
|
224
|
+
for await (const msg of client.fetch(recentUids.map(String), { envelope: true, uid: true, flags: true })) {
|
|
225
|
+
messages.push({
|
|
226
|
+
uid: msg.uid,
|
|
227
|
+
from: formatAddressList(msg.envelope?.from),
|
|
228
|
+
subject: msg.envelope?.subject || "(no subject)",
|
|
229
|
+
date: msg.envelope?.date?.toISOString(),
|
|
230
|
+
read: msg.flags?.has("\\Seen")
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return { result: { messages, total: uids.length, showing: messages.length } };
|
|
234
|
+
} finally {
|
|
235
|
+
lock.release();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
async function emailFolders(ctx, _params) {
|
|
240
|
+
return withImap(ctx, async (client) => {
|
|
241
|
+
const folders = await client.list();
|
|
242
|
+
const result = folders.map((f) => ({
|
|
243
|
+
path: f.path,
|
|
244
|
+
name: f.name,
|
|
245
|
+
specialUse: f.specialUse || null
|
|
246
|
+
}));
|
|
247
|
+
return { result: { folders: result } };
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
async function emailMove(ctx, params) {
|
|
251
|
+
const { uid, from, to } = params;
|
|
252
|
+
if (!uid || !to) return { error: "Missing required parameters: uid, to (destination folder)" };
|
|
253
|
+
return withImap(ctx, async (client) => {
|
|
254
|
+
const lock = await client.getMailboxLock(from || "INBOX");
|
|
255
|
+
try {
|
|
256
|
+
await client.messageMove(String(uid), to, { uid: true });
|
|
257
|
+
return { result: { uid, movedTo: to, status: "moved" } };
|
|
258
|
+
} finally {
|
|
259
|
+
lock.release();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
async function emailDelete(ctx, params) {
|
|
264
|
+
const { uid, folder, permanent } = params;
|
|
265
|
+
if (!uid) return { error: "Missing required parameter: uid" };
|
|
266
|
+
return withImap(ctx, async (client) => {
|
|
267
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
268
|
+
try {
|
|
269
|
+
if (permanent) {
|
|
270
|
+
await client.messageFlagsAdd(String(uid), ["\\Deleted"], { uid: true });
|
|
271
|
+
await client.messageDelete(String(uid), { uid: true });
|
|
272
|
+
} else {
|
|
273
|
+
await client.messageMove(String(uid), "Trash", { uid: true });
|
|
274
|
+
}
|
|
275
|
+
return { result: { uid, status: permanent ? "deleted" : "trashed" } };
|
|
276
|
+
} finally {
|
|
277
|
+
lock.release();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async function emailMarkRead(ctx, params) {
|
|
282
|
+
const { uid, folder, unread } = params;
|
|
283
|
+
if (!uid) return { error: "Missing required parameter: uid" };
|
|
284
|
+
return withImap(ctx, async (client) => {
|
|
285
|
+
const lock = await client.getMailboxLock(folder || "INBOX");
|
|
286
|
+
try {
|
|
287
|
+
if (unread) {
|
|
288
|
+
await client.messageFlagsRemove(String(uid), ["\\Seen"], { uid: true });
|
|
289
|
+
} else {
|
|
290
|
+
await client.messageFlagsAdd(String(uid), ["\\Seen"], { uid: true });
|
|
291
|
+
}
|
|
292
|
+
return { result: { uid, status: unread ? "marked_unread" : "marked_read" } };
|
|
293
|
+
} finally {
|
|
294
|
+
lock.release();
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
var TOOL_MAP = {
|
|
299
|
+
email_send: emailSend,
|
|
300
|
+
email_reply: emailReply,
|
|
301
|
+
email_forward: emailForward,
|
|
302
|
+
email_search: emailSearch,
|
|
303
|
+
email_read: emailRead,
|
|
304
|
+
email_list: emailList,
|
|
305
|
+
email_folders: emailFolders,
|
|
306
|
+
email_move: emailMove,
|
|
307
|
+
email_delete: emailDelete,
|
|
308
|
+
email_mark_read: emailMarkRead
|
|
309
|
+
};
|
|
310
|
+
function getSmtpEmailTools() {
|
|
311
|
+
return Object.keys(TOOL_MAP);
|
|
312
|
+
}
|
|
313
|
+
async function executeSmtpEmailTool(toolId, ctx, params) {
|
|
314
|
+
const handler = TOOL_MAP[toolId];
|
|
315
|
+
if (!handler) return { error: `Unknown SMTP email tool: ${toolId}` };
|
|
316
|
+
try {
|
|
317
|
+
return await handler(ctx, params);
|
|
318
|
+
} catch (e) {
|
|
319
|
+
const msg = e.message || String(e);
|
|
320
|
+
if (msg.includes("AUTHENTICATIONFAILED") || msg.includes("Invalid credentials")) {
|
|
321
|
+
return { error: "Email authentication failed. Check your email/password in agent settings. For Gmail, you need an App Password (not regular password)." };
|
|
322
|
+
}
|
|
323
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND")) {
|
|
324
|
+
return { error: `Cannot connect to email server: ${msg}. Check SMTP/IMAP host settings.` };
|
|
325
|
+
}
|
|
326
|
+
return { error: msg };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
export {
|
|
330
|
+
executeSmtpEmailTool,
|
|
331
|
+
getSmtpEmailTools
|
|
332
|
+
};
|
|
@@ -141,3 +141,5 @@
|
|
|
141
141
|
2026-03-05 19:22:34: 2026-03-05T18:22:34Z ERR Request failed error="stream 365 canceled by remote with error code 0" connIndex=0 dest=https://enterprise.agenticmail.io/api/engine/agent-status-stream event=0 ip=198.41.192.107 type=http
|
|
142
142
|
2026-03-05 19:23:02: 2026-03-05T18:23:02Z ERR error="stream 357 canceled by remote with error code 0" connIndex=0 event=1 ingressRule=0 originService=http://localhost:3100
|
|
143
143
|
2026-03-05 19:23:02: 2026-03-05T18:23:02Z ERR Request failed error="stream 357 canceled by remote with error code 0" connIndex=0 dest=https://enterprise.agenticmail.io/api/engine/cluster/stream event=0 ip=198.41.192.107 type=http
|
|
144
|
+
2026-03-05 19:53:34: 2026-03-05T18:53:34Z ERR error="stream 405 canceled by remote with error code 0" connIndex=0 event=1 ingressRule=0 originService=http://localhost:3100
|
|
145
|
+
2026-03-05 19:53:34: 2026-03-05T18:53:34Z ERR Request failed error="stream 405 canceled by remote with error code 0" connIndex=0 dest=https://enterprise.agenticmail.io/api/engine/agent-status-stream?agentId=67ba24f1-c8af-40b4-9df5-c05b81fc1e7a event=0 ip=198.41.192.107 type=http
|