On a shared, group or aliased mailbox every reply, reply-all and forward
went out as `identities[0]` - the account owner - whichever mailbox was
open. `autoSelectReplyIdentity` fused two behaviours: matching one of the
user's OWN identities, which never rewrites `From:`, and the domain
catch-all, which puts an address they have not configured into `From:`.
Only the first is safe for everyone, so it is now unconditional; the
rewrite stays behind the setting, which is what its description promises.
`findReplyIdentityId` already implemented that match and was referenced
only from tests.
`forward` is admitted to the match - it was excluded, so a forward from a
shared mailbox went out as the owner - but never takes the rewrite: a reply
continues a thread whose participants know the addressing, while a forward
introduces a rewritten From to a recipient the user just typed. Quick reply
matches own identities only, having no From row to show or correct a
rewrite, and now falls back to the primary's signature as the composer
does, so a shared-mailbox quick reply is still signed.
`findReplyIdentityId` now scans recipients in To, Cc, Bcc order rather than
scanning identities, and prefers an untagged identity over a differently
tagged sibling. Scanning identities let their order decide, and
`sortIdentities` puts the login's own address first - so `To: team@,
Cc: you@` replied as you, the case this is meant to fix.
Automatic selection is restricted to the active account: `composerClient`
follows the chosen identity, and a reply or forward still carries blobIds
only its own account's server can resolve. The dropdown still offers every
account's identities to pick by hand.
New messages are deliberately left gated: `composeFromAccountEmail` falls
back to `AccountEntry.email`, written once at first login, so resolving it
unconditionally would override a user-chosen default sender identity (#507).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Composing a new message while a shared/group folder was selected started
it as the reaching login's primary address instead of the shared one,
even when a matching send-as identity existed.
`composeFromAccountEmail` was resolved from
`getAccountById(viewingAccountId ?? activeAccountId)`. A delegated
mailbox has no separate login and no AccountEntry, and
`setViewingAccount` is only ever called with `null`, so selecting a
shared folder leaves both ids pointing at the primary account:
`findComposeIdentityId` was handed the wrong address and correctly
matched the primary identity.
Resolve the address from the selected mailbox instead, falling back to
the account lookup for own folders. `accountName` is the JMAP
`Account.name`, which RFC 8620 describes as "e.g., the email address of
the account"; a server that puts a human label there produces no
identity match and the composer keeps the primary identity, which is the
previous behaviour. Replies are unaffected - `composeFromAccountEmail`
is only read when `mode === 'compose'`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reopening a draft reset the composer's From to the default identity. The
edit-draft handler matched the draft's saved From against the active-account
identity list by email only, so two identities sharing an address (a default +
an alias differing by name) collided — the wrong one was picked, or with
cross-account namespaced ids none was.
Add findDraftIdentityId (name+email, normalized, +tag fallback) and match against
the same list the composer renders (the flat cross-account list when multi-
account is on). Wired into both the classic and Pro edit-draft paths. Unit tests
plus the un-pinned 07-drafts integration spec.
Starting a new message while viewing a specific mailbox/account now defaults
the From identity to that mailbox instead of the global primary identity, so
composing from info@ sends as info@. Mirrors the existing reply-time identity
match and rides the same autoSelectReplyIdentity setting; reply/replyAll/forward
keep resolving from the original recipients. Matches exact then +tag-stripped.
Extracts findComposeIdentityId into lib/reply-identity.ts with unit tests.
Adds an Override toggle in the composer's From row. When enabled, name
and address become free-text inputs. Mail is still submitted through the
selected identity, but the outgoing message's From: header — and the
SMTP envelope MAIL FROM when different — is set from the override.
The existing "Auto-select Reply Address" setting is extended: if the
incoming message was addressed to an alias on a domain that matches one
of your identities but isn't itself an identity (classic domain catch-
all), it now auto-enables Override and pre-fills the alias. Quick reply
honors the same resolution. The setting is relabeled to reflect the
broader behavior.
JMAP: client.sendEmail gains an optional envelopeMailFrom; when set, the
EmailSubmission includes an explicit envelope with that mailFrom and the
to/cc/bcc as rcptTo so header-From and envelope can diverge (JMAP §7.3).
S/MIME: override is incompatible with sign/encrypt and is refused with a
clear error — signing a different visible From from the identity's
certificate Subject would produce messages clients reject.
Tests: resolveReplyFrom covers exact match, sub-address stripping,
catch-all detection, identity preference, and foreign-domain null.