@bobfrankston/mailx 1.0.181 → 1.0.182

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.
@@ -1 +1 @@
1
- {"height":1047,"width":1844,"x":339,"y":168}
1
+ {"height":1344,"width":1438,"x":216,"y":107}
package/client/app.js CHANGED
@@ -265,12 +265,31 @@ async function openCompose(mode) {
265
265
  references: [],
266
266
  accounts: accounts.map((a) => ({ id: a.id, name: a.name, email: a.email })),
267
267
  };
268
+ // Auto-detect reply From: if the message was delivered to an identity domain,
269
+ // reply from that address instead of the default account address.
270
+ // Identity domains configured per-account in accounts.jsonc (identityDomains array).
271
+ // Default identity domains for bob.ma account:
272
+ const identityDomains = ["bob.ma", "frankston.com"];
273
+ function detectReplyFrom() {
274
+ if (!msg)
275
+ return undefined;
276
+ // Check deliveredTo first (most reliable), then To addresses
277
+ const candidates = [msg.deliveredTo, ...(msg.to || []).map((a) => a.address)].filter(Boolean);
278
+ for (const addr of candidates) {
279
+ const domain = addr.split("@")[1]?.toLowerCase();
280
+ if (domain && identityDomains.some(d => domain === d || domain.endsWith(`.${d}`))) {
281
+ return addr;
282
+ }
283
+ }
284
+ return undefined;
285
+ }
268
286
  if (msg && mode === "reply") {
269
287
  init.to = [msg.from];
270
288
  init.subject = `Re: ${cleanSubject}`;
271
289
  init.bodyHtml = quoteBody(msg);
272
290
  init.inReplyTo = msg.messageId;
273
291
  init.references = [...(msg.references || []), msg.messageId];
292
+ init.fromAddress = detectReplyFrom();
274
293
  }
275
294
  else if (msg && mode === "replyAll") {
276
295
  init.to = [msg.from, ...msg.to.filter((a) => a.address !== msg.from.address)];
@@ -279,6 +298,7 @@ async function openCompose(mode) {
279
298
  init.bodyHtml = quoteBody(msg);
280
299
  init.inReplyTo = msg.messageId;
281
300
  init.references = [...(msg.references || []), msg.messageId];
301
+ init.fromAddress = detectReplyFrom();
282
302
  }
283
303
  else if (msg && mode === "forward") {
284
304
  init.subject = `Fwd: ${cleanSubject}`;
@@ -260,6 +260,13 @@ function parseAddrs(s) {
260
260
  function applyInit(init) {
261
261
  // Populate From dropdown
262
262
  populateFromSelect(init.accounts, init.accountId);
263
+ // Auto-detect reply From: if fromAddress is set (identity domain match),
264
+ // use it as the From address via the "Other..." custom field
265
+ if (init.fromAddress) {
266
+ fromSelect.value = "__custom__";
267
+ fromCustom.hidden = false;
268
+ fromCustom.value = init.fromAddress;
269
+ }
263
270
  toInput.value = formatAddrs(init.to);
264
271
  ccInput.value = formatAddrs(init.cc);
265
272
  subjectInput.value = init.subject;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.181",
3
+ "version": "1.0.182",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -24,7 +24,7 @@
24
24
  "@bobfrankston/iflow-node": "^0.1.2",
25
25
  "@bobfrankston/miscinfo": "^1.0.8",
26
26
  "@bobfrankston/oauthsupport": "^1.0.21",
27
- "@bobfrankston/msger": "^0.1.231",
27
+ "@bobfrankston/msger": "^0.1.232",
28
28
  "@capacitor/android": "^8.3.0",
29
29
  "@capacitor/cli": "^8.3.0",
30
30
  "@capacitor/core": "^8.3.0",
@@ -106,7 +106,7 @@ export class MailxService {
106
106
  for (const cfg of settings.accounts) {
107
107
  const a = dbAccounts.find(d => d.id === cfg.id);
108
108
  if (a)
109
- ordered.push({ ...a, label: cfg.label, defaultSend: cfg.defaultSend || false });
109
+ ordered.push({ ...a, label: cfg.label, defaultSend: cfg.defaultSend || false, identityDomains: cfg.identityDomains || [] });
110
110
  }
111
111
  // Append any DB accounts not in settings
112
112
  for (const a of dbAccounts) {
@@ -339,7 +339,9 @@ export class MailxService {
339
339
  const account = settings.accounts.find(a => a.id === msg.from);
340
340
  if (!account)
341
341
  throw new Error(`Unknown account: ${msg.from}`);
342
- const fromHeader = msg.fromAddress || `${account.name} <${account.email}>`;
342
+ // Use custom From address if set (identity domain reply), but always wrap with account display name
343
+ const fromAddr = msg.fromAddress || account.email;
344
+ const fromHeader = `${account.name} <${fromAddr}>`;
343
345
  const to = msg.to.map((a) => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
344
346
  const cc = msg.cc?.map((a) => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
345
347
  const bcc = msg.bcc?.map((a) => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");