@bobfrankston/mailx-types 0.1.110 → 0.1.111

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.
@@ -38,6 +38,15 @@ export interface ListIdentity {
38
38
  /** The reader's subscribed address as the list itself states it (groups.io
39
39
  * footer), or "". */
40
40
  listSubscriber: string;
41
+ /** The author's real address when the list rewrote From into an
42
+ * undeliverable stand-in, else "". groups.io turns
43
+ * `bernardgreenberg@msn.com` into `"Bernard Greenberg via groups.io"
44
+ * <bernardgreenberg=msn.com@groups.io>` (so his own domain's DMARC policy
45
+ * doesn't reject the list's copy) and refuses mail sent to that:
46
+ * "510 5.1.1 … is not a real mailbox. To reply to this person, send your
47
+ * message to bernardgreenberg@msn.com" (Bob's bounce, 2026-10-26). The
48
+ * real address is in Resent-From. (2026-10-26, Claude Code (Opus 5.5).) */
49
+ listAuthor: string;
41
50
  }
42
51
  /** Read the delivery and list facts out of a parsed message. */
43
52
  export declare function readListIdentity(headerLines: readonly ListHeaderLine[], bodyText: string, bodyHtml: string): ListIdentity;
package/list-identity.js CHANGED
@@ -68,7 +68,7 @@ export function readListIdentity(headerLines, bodyText, bodyHtml) {
68
68
  const rawListId = headerValues(headerLines, "list-id")[0] || "";
69
69
  const listId = ((rawListId.match(/<([^>]+)>/)?.[1]) || rawListId).trim().toLowerCase();
70
70
  if (!listId)
71
- return { deliveredTo, listId: "", listAddresses: [], listSubscriber: "" };
71
+ return { deliveredTo, listId: "", listAddresses: [], listSubscriber: "", listAuthor: "" };
72
72
  const listPost = (headerValues(headerLines, "list-post")[0] || "").match(/<mailto:([^>?]+)/i)?.[1] || "";
73
73
  const listAddresses = [];
74
74
  for (const candidate of [listPost, headerValues(headerLines, "reply-to")[0], headerValues(headerLines, "sender")[0]]) {
@@ -79,11 +79,19 @@ export function readListIdentity(headerLines, bodyText, bodyHtml) {
79
79
  // Only groups.io states the subscriber, and only in its footer; the List-Id
80
80
  // gate keeps the pattern off every other message's body.
81
81
  let listSubscriber = "";
82
+ let listAuthor = "";
82
83
  if (listId === "groups.io" || listId.endsWith(".groups.io")) {
83
84
  const m = (bodyText || "").match(GROUPS_IO_SUBSCRIBER) || (bodyHtml || "").match(GROUPS_IO_SUBSCRIBER);
84
85
  if (m)
85
86
  listSubscriber = m[1];
87
+ // A rewritten From is `local=domain@groups.io`. Resent-From carries
88
+ // the original; failing that, the rewrite itself encodes it (the
89
+ // LAST `=` separates local part from domain).
90
+ const from = bareAddress(headerValues(headerLines, "from")[0] || "");
91
+ const rewritten = from.match(/^(.+)=([^=@]+)@groups\.io$/);
92
+ if (rewritten)
93
+ listAuthor = bareAddress(headerValues(headerLines, "resent-from")[0] || "") || `${rewritten[1]}@${rewritten[2]}`;
86
94
  }
87
- return { deliveredTo, listId, listAddresses, listSubscriber };
95
+ return { deliveredTo, listId, listAddresses, listSubscriber, listAuthor };
88
96
  }
89
97
  //# sourceMappingURL=list-identity.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-types",
3
- "version": "0.1.110",
3
+ "version": "0.1.111",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",