@agenticmail/api 0.9.18 → 0.9.20
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/index.js +27 -12
- package/package.json +1 -1
- package/public/js/message-view.js +18 -3
package/dist/index.js
CHANGED
|
@@ -2468,9 +2468,10 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2468
2468
|
res.status(400).json({ error: "Invalid UID" });
|
|
2469
2469
|
return;
|
|
2470
2470
|
}
|
|
2471
|
+
const folder = req.body?.folder || "INBOX";
|
|
2471
2472
|
const password = getAgentPassword(agent);
|
|
2472
2473
|
const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
|
|
2473
|
-
await receiver.markUnseen(uid);
|
|
2474
|
+
await receiver.markUnseen(uid, folder);
|
|
2474
2475
|
invalidateParsedMessage(agent.id, uid);
|
|
2475
2476
|
res.json({ ok: true });
|
|
2476
2477
|
} catch (err) {
|
|
@@ -2673,6 +2674,17 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2673
2674
|
next(err);
|
|
2674
2675
|
}
|
|
2675
2676
|
});
|
|
2677
|
+
async function resolveSpamFolder(receiver) {
|
|
2678
|
+
const folders = await receiver.listFolders();
|
|
2679
|
+
const junkRe = /^junk\b|^junk mail\b|^spam\b/i;
|
|
2680
|
+
const found = folders.find((f) => f.specialUse === "\\Junk")?.path ?? folders.find((f) => junkRe.test(f.name) || junkRe.test(f.path))?.path;
|
|
2681
|
+
if (found) return found;
|
|
2682
|
+
try {
|
|
2683
|
+
await receiver.createFolder("Junk Mail");
|
|
2684
|
+
} catch {
|
|
2685
|
+
}
|
|
2686
|
+
return "Junk Mail";
|
|
2687
|
+
}
|
|
2676
2688
|
router.get("/mail/spam", requireAgent, async (req, res, next) => {
|
|
2677
2689
|
try {
|
|
2678
2690
|
const agent = req.agent;
|
|
@@ -2680,15 +2692,16 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2680
2692
|
const offset = Math.max(parseInt(req.query.offset) || 0, 0);
|
|
2681
2693
|
const password = getAgentPassword(agent);
|
|
2682
2694
|
const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
|
|
2695
|
+
const spamFolder = await resolveSpamFolder(receiver);
|
|
2683
2696
|
let mailboxInfo;
|
|
2684
2697
|
try {
|
|
2685
|
-
mailboxInfo = await receiver.getMailboxInfo(
|
|
2698
|
+
mailboxInfo = await receiver.getMailboxInfo(spamFolder);
|
|
2686
2699
|
} catch {
|
|
2687
|
-
res.json({ messages: [], count: 0, total: 0, folder:
|
|
2700
|
+
res.json({ messages: [], count: 0, total: 0, folder: spamFolder });
|
|
2688
2701
|
return;
|
|
2689
2702
|
}
|
|
2690
|
-
const envelopes = await receiver.listEnvelopes(
|
|
2691
|
-
res.json({ messages: envelopes, count: envelopes.length, total: mailboxInfo.exists, folder:
|
|
2703
|
+
const envelopes = await receiver.listEnvelopes(spamFolder, { limit, offset });
|
|
2704
|
+
res.json({ messages: envelopes, count: envelopes.length, total: mailboxInfo.exists, folder: spamFolder });
|
|
2692
2705
|
} catch (err) {
|
|
2693
2706
|
next(err);
|
|
2694
2707
|
}
|
|
@@ -2793,12 +2806,13 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2793
2806
|
const folder = req.body?.folder || "INBOX";
|
|
2794
2807
|
const password = getAgentPassword(agent);
|
|
2795
2808
|
const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2809
|
+
const spamFolder = await resolveSpamFolder(receiver);
|
|
2810
|
+
if (spamFolder === folder) {
|
|
2811
|
+
res.status(400).json({ error: "Message already in spam" });
|
|
2812
|
+
return;
|
|
2799
2813
|
}
|
|
2800
|
-
await receiver.moveMessage(uid, folder,
|
|
2801
|
-
res.json({ ok: true, movedToSpam: true });
|
|
2814
|
+
await receiver.moveMessage(uid, folder, spamFolder);
|
|
2815
|
+
res.json({ ok: true, movedToSpam: true, spam: spamFolder });
|
|
2802
2816
|
} catch (err) {
|
|
2803
2817
|
next(err);
|
|
2804
2818
|
}
|
|
@@ -2813,8 +2827,9 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2813
2827
|
}
|
|
2814
2828
|
const password = getAgentPassword(agent);
|
|
2815
2829
|
const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
|
|
2816
|
-
await receiver
|
|
2817
|
-
|
|
2830
|
+
const spamFolder = await resolveSpamFolder(receiver);
|
|
2831
|
+
await receiver.moveMessage(uid, spamFolder, "INBOX");
|
|
2832
|
+
res.json({ ok: true, movedToInbox: true, spam: spamFolder });
|
|
2818
2833
|
} catch (err) {
|
|
2819
2834
|
next(err);
|
|
2820
2835
|
}
|
package/package.json
CHANGED
|
@@ -36,7 +36,20 @@ export async function openMessage(uid) {
|
|
|
36
36
|
document.getElementById('msg-delete').addEventListener('click', () => deleteMessage());
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
|
-
|
|
39
|
+
// Pass the current folder so the API fetches from the right
|
|
40
|
+
// mailbox — Spam / Archive / Trash UIDs don't exist in INBOX,
|
|
41
|
+
// and the API defaults `folder` to INBOX when omitted. Without
|
|
42
|
+
// this, opening a message from any non-Inbox folder 404'd
|
|
43
|
+
// with `MESSAGE_NOT_FOUND` because UID N existed in (say) Junk
|
|
44
|
+
// Mail but the API looked in INBOX.
|
|
45
|
+
//
|
|
46
|
+
// We resolve the IMAP folder name via state.folderNames (the
|
|
47
|
+
// map populated by /mail/folders auto-discovery) so renames
|
|
48
|
+
// like Stalwart's "Junk Mail" vs "Spam" are handled in one
|
|
49
|
+
// place. "inbox" maps to "INBOX" by convention.
|
|
50
|
+
const imap = state.folderNames?.[state.selectedFolder] ?? 'INBOX';
|
|
51
|
+
const qs = imap && imap !== 'INBOX' ? `?folder=${encodeURIComponent(imap)}` : '';
|
|
52
|
+
const msg = await apiGet(`/mail/messages/${uid}${qs}`, { agentKey: state.selectedAgent.apiKey });
|
|
40
53
|
state.currentMessage = msg;
|
|
41
54
|
renderMessage(msg);
|
|
42
55
|
} catch (err) {
|
|
@@ -220,7 +233,8 @@ function renderThreadQuote(dateRaw, sender, quotedBody) {
|
|
|
220
233
|
async function markUnread() {
|
|
221
234
|
if (!state.currentMessage || !state.selectedAgent) return;
|
|
222
235
|
try {
|
|
223
|
-
|
|
236
|
+
const imap = state.folderNames?.[state.selectedFolder] ?? 'INBOX';
|
|
237
|
+
await apiPost(`/mail/messages/${state.selectedUid}/unseen`, { folder: imap }, { agentKey: state.selectedAgent.apiKey });
|
|
224
238
|
toast('Marked unread.');
|
|
225
239
|
location.hash = `#/folder/${state.selectedFolder ?? 'inbox'}`;
|
|
226
240
|
await loadList(state.selectedAgent, state.selectedFolder);
|
|
@@ -262,7 +276,8 @@ async function markSpam() {
|
|
|
262
276
|
});
|
|
263
277
|
if (!ok) return;
|
|
264
278
|
try {
|
|
265
|
-
|
|
279
|
+
const imap = state.folderNames?.[state.selectedFolder] ?? 'INBOX';
|
|
280
|
+
await apiPost(`/mail/messages/${state.selectedUid}/spam`, { folder: imap }, { agentKey: state.selectedAgent.apiKey });
|
|
266
281
|
toast('Reported as spam.');
|
|
267
282
|
location.hash = `#/folder/${state.selectedFolder ?? 'inbox'}`;
|
|
268
283
|
await loadList(state.selectedAgent, state.selectedFolder);
|