@bobfrankston/rmfmail 1.2.310 → 1.2.313
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/.commitmsg +21 -12
- package/.llm/trusted-lists.md +49 -0
- package/TODO.md +2 -2
- package/client/android-bootstrap.bundle.js +78 -15
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/app.bundle.js +84 -2
- package/client/app.bundle.js.map +2 -2
- package/client/components/message-viewer.js +128 -1
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +123 -2
- package/client/compose/compose.bundle.js +1 -1
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/lib/api-client.js +1 -1
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +3 -3
- package/client/styles/components.css +3 -0
- package/docs/allowlist.md +28 -3
- package/docs/spam-false-positives.md +23 -0
- package/npmchanges.md +58 -0
- package/package.json +5 -5
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts +3 -1
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +4 -2
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +6 -4
- package/packages/mailx-service/package.json +1 -1
- package/packages/mailx-settings/docs/allowlist.md +28 -3
- package/packages/mailx-settings/docs/spam-false-positives.md +23 -0
- package/packages/mailx-settings/index.d.ts +1 -0
- package/packages/mailx-settings/index.d.ts.map +1 -1
- package/packages/mailx-settings/index.js +7 -0
- package/packages/mailx-settings/index.js.map +1 -1
- package/packages/mailx-settings/index.ts +7 -0
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store/store.d.ts.map +1 -1
- package/packages/mailx-store/store.js +3 -0
- package/packages/mailx-store/store.js.map +1 -1
- package/packages/mailx-store/store.ts +3 -0
- package/packages/mailx-store-web/package.json +1 -1
- package/packages/mailx-store-web/web-service.d.ts +3 -2
- package/packages/mailx-store-web/web-service.d.ts.map +1 -1
- package/packages/mailx-store-web/web-service.js +4 -2
- package/packages/mailx-store-web/web-service.js.map +1 -1
- package/packages/mailx-store-web/web-service.ts +6 -4
- package/packages/mailx-store-web/web-settings.d.ts +1 -0
- package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
- package/packages/mailx-store-web/web-settings.js +2 -0
- package/packages/mailx-store-web/web-settings.js.map +1 -1
- package/packages/mailx-store-web/web-settings.ts +2 -0
- package/packages/mailx-types/index.d.ts +2 -2
- package/packages/mailx-types/index.d.ts.map +1 -1
- package/packages/mailx-types/index.js +1 -1
- package/packages/mailx-types/index.js.map +1 -1
- package/packages/mailx-types/index.ts +2 -2
- package/packages/mailx-types/package.json +1 -1
- package/packages/mailx-types/trust.d.ts +35 -0
- package/packages/mailx-types/trust.d.ts.map +1 -1
- package/packages/mailx-types/trust.js +115 -8
- package/packages/mailx-types/trust.js.map +1 -1
- package/packages/mailx-types/trust.ts +139 -8
package/client/app.bundle.js
CHANGED
|
@@ -356,7 +356,7 @@ function trustSenderOrDomain(type, value) {
|
|
|
356
356
|
return ipc().trustSenderOrDomain?.(type, value) ?? Promise.resolve({ trusted: false });
|
|
357
357
|
}
|
|
358
358
|
function getAllowlist() {
|
|
359
|
-
return ipc().getAllowlist?.() ?? Promise.resolve({ senders: [], domains: [], recipients: [], flaggedSenders: [], flaggedDomains: [], trustedSenders: [], trustedDomains: [], trustedIntermediaries: [] });
|
|
359
|
+
return ipc().getAllowlist?.() ?? Promise.resolve({ senders: [], domains: [], recipients: [], flaggedSenders: [], flaggedDomains: [], trustedSenders: [], trustedDomains: [], trustedIntermediaries: [], trustedLists: [] });
|
|
360
360
|
}
|
|
361
361
|
function flagSenderOrDomain(type, value) {
|
|
362
362
|
return ipc().flagSenderOrDomain?.(type, value) ?? Promise.resolve({ flagged: false });
|
|
@@ -2930,6 +2930,38 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
|
|
|
2930
2930
|
items.push({ label: "", action: () => {
|
|
2931
2931
|
}, separator: true });
|
|
2932
2932
|
}
|
|
2933
|
+
const listSpam = msg.spamScore;
|
|
2934
|
+
if (listSpam?.listProved && listSpam.listId) {
|
|
2935
|
+
const listId = listSpam.listId;
|
|
2936
|
+
const untrust = !!listSpam.listTrusted;
|
|
2937
|
+
items.push({
|
|
2938
|
+
label: untrust ? `\u2717 Stop trusting the ${listId} mailing list` : `\u2713 Trust the ${listId} mailing list`,
|
|
2939
|
+
action: async () => {
|
|
2940
|
+
const st = document.getElementById("status-sync");
|
|
2941
|
+
try {
|
|
2942
|
+
const res = await trustSenderOrDomain("list", listId);
|
|
2943
|
+
if (!res || !!res.trusted === untrust)
|
|
2944
|
+
throw new Error("the list did not save");
|
|
2945
|
+
listSpam.listTrusted = res.trusted;
|
|
2946
|
+
if (res.trusted) {
|
|
2947
|
+
document.querySelector(".mv-spamscore")?.remove();
|
|
2948
|
+
document.querySelector(".mv-spamscore-action")?.remove();
|
|
2949
|
+
document.querySelector(".mv-trust")?.remove();
|
|
2950
|
+
}
|
|
2951
|
+
if (st)
|
|
2952
|
+
st.textContent = res.trusted ? `Trusting the ${listId} mailing list` : `No longer trusting the ${listId} mailing list \u2014 reopen the message to see its score again`;
|
|
2953
|
+
} catch (e2) {
|
|
2954
|
+
if (st) {
|
|
2955
|
+
st.textContent = `Couldn't trust the ${listId} list \u2014 ${e2?.message || e2}`;
|
|
2956
|
+
st.style.color = "oklch(0.65 0.2 25)";
|
|
2957
|
+
}
|
|
2958
|
+
console.error("[allowlist] trust list failed:", e2);
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
});
|
|
2962
|
+
items.push({ label: "", action: () => {
|
|
2963
|
+
}, separator: true });
|
|
2964
|
+
}
|
|
2933
2965
|
}
|
|
2934
2966
|
if (omitted > 0) {
|
|
2935
2967
|
items.push({
|
|
@@ -3159,9 +3191,34 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
|
|
|
3159
3191
|
chip.className = `mv-spamscore mv-spamscore-${level}`;
|
|
3160
3192
|
const why = (spam.reasons || []).length ? "\n\n" + spam.reasons.join("\n") : "";
|
|
3161
3193
|
const provedNote = spam.provedBy === "dkim" ? "the sending domain signed it and the signature verified" : spam.provedBy === "trusted" ? "it never passed through an untrusted host" : "the sending domain passed DMARC";
|
|
3162
|
-
chip.title = (level === "bulk" ? spam.proved ? spam.bulkOnly ? `Scored by bulk-mail or blocklist rules; ${provedNote}, so the sender is proved.` : `${provedNote[0].toUpperCase()}${provedNote.slice(1)}, so the sender is proved. Not every rule that scored is a bulk-mail test \u2014 they are listed below.` : spam.bulkOnly ? "Every rule that scored is a bulk-mail test \u2014 none of them test who sent this." : "No forgery rule scored. The rules that did are listed below." : level === "high" ? "Your mail server scored this at or above its spam threshold and flagged it." : "Below your server's spam threshold, but more than halfway to it.") + why
|
|
3194
|
+
chip.title = (level === "bulk" ? spam.proved ? spam.bulkOnly ? `Scored by bulk-mail or blocklist rules; ${provedNote}, so the sender is proved.` : `${provedNote[0].toUpperCase()}${provedNote.slice(1)}, so the sender is proved. Not every rule that scored is a bulk-mail test \u2014 they are listed below.` : spam.bulkOnly ? "Every rule that scored is a bulk-mail test \u2014 none of them test who sent this." : "No forgery rule scored. The rules that did are listed below." : level === "high" ? "Your mail server scored this at or above its spam threshold and flagged it." : "Below your server's spam threshold, but more than halfway to it.") + why + (spam.listProved && spam.listId && !spam.listTrusted ? `
|
|
3195
|
+
|
|
3196
|
+
Delivered by the ${spam.listId} mailing list, which your server proved sent it. Right-click the From address to trust the list.` : "");
|
|
3163
3197
|
chip.textContent = `spam score ${spam.score} of ${spam.threshold}`;
|
|
3164
3198
|
bodyEl.appendChild(chip);
|
|
3199
|
+
if (spam.listProved && spam.listId && !spam.listTrusted) {
|
|
3200
|
+
const listId = spam.listId;
|
|
3201
|
+
const b = document.createElement("button");
|
|
3202
|
+
b.className = "mv-trust-action mv-spamscore-action";
|
|
3203
|
+
b.textContent = `Trust the ${listId} list`;
|
|
3204
|
+
b.title = `Delivered by the ${listId} mailing list, which your server proved sent it. Trusting the list hides this score on every post the list delivers.`;
|
|
3205
|
+
b.addEventListener("click", async () => {
|
|
3206
|
+
b.disabled = true;
|
|
3207
|
+
try {
|
|
3208
|
+
const res = await trustSenderOrDomain("list", listId);
|
|
3209
|
+
if (!res?.trusted)
|
|
3210
|
+
throw new Error("the list did not save");
|
|
3211
|
+
spam.listTrusted = true;
|
|
3212
|
+
chip.remove();
|
|
3213
|
+
b.remove();
|
|
3214
|
+
document.querySelector(".mv-trust")?.remove();
|
|
3215
|
+
} catch (e) {
|
|
3216
|
+
b.disabled = false;
|
|
3217
|
+
b.textContent = `Could not save: ${e?.message || e}`;
|
|
3218
|
+
}
|
|
3219
|
+
});
|
|
3220
|
+
bodyEl.appendChild(b);
|
|
3221
|
+
}
|
|
3165
3222
|
}
|
|
3166
3223
|
const trust = msg.trust || [];
|
|
3167
3224
|
if (trust.length) {
|
|
@@ -3202,6 +3259,31 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
|
|
|
3202
3259
|
}
|
|
3203
3260
|
warn.appendChild(actions);
|
|
3204
3261
|
}
|
|
3262
|
+
const lists = worst === "danger" ? [] : Array.from(new Set(trust.map((f) => f.list).filter(Boolean)));
|
|
3263
|
+
if (lists.length) {
|
|
3264
|
+
const actions = document.createElement("div");
|
|
3265
|
+
actions.className = "mv-trust-actions";
|
|
3266
|
+
for (const listId of lists) {
|
|
3267
|
+
const b = document.createElement("button");
|
|
3268
|
+
b.className = "mv-trust-action";
|
|
3269
|
+
b.textContent = `Trust the ${listId} list`;
|
|
3270
|
+
b.addEventListener("click", async () => {
|
|
3271
|
+
b.disabled = true;
|
|
3272
|
+
try {
|
|
3273
|
+
const res = await trustSenderOrDomain("list", listId);
|
|
3274
|
+
if (!res?.trusted)
|
|
3275
|
+
throw new Error("the list did not save");
|
|
3276
|
+
warn.remove();
|
|
3277
|
+
document.querySelector(".mv-spamscore")?.remove();
|
|
3278
|
+
} catch (e) {
|
|
3279
|
+
b.disabled = false;
|
|
3280
|
+
b.textContent = `Could not save: ${e?.message || e}`;
|
|
3281
|
+
}
|
|
3282
|
+
});
|
|
3283
|
+
actions.appendChild(b);
|
|
3284
|
+
}
|
|
3285
|
+
warn.appendChild(actions);
|
|
3286
|
+
}
|
|
3205
3287
|
const vias = worst === "danger" ? [] : Array.from(new Set(trust.map((f) => f.via).filter(Boolean)));
|
|
3206
3288
|
if (vias.length) {
|
|
3207
3289
|
const actions = document.createElement("div");
|