A website contact form mails the site's own address: From and To are both info@thesite, and the person who filled the form in is in Reply-To. Replying addressed the draft to info@thesite -- the site's own desk -- instead of to them. The reply already knows two shapes. A message somebody sent me is answered to its Reply-To, which is what that header is for. A message *I* sent is answered to the people I wrote to, and deliberately not to my own Reply-To, which is where answers to me belong and would send my reply to myself. A contact form passes the test for the second: every address in From is mine. So it fell down the chain the second shape keeps for a message with nobody obvious to answer -- To without me, then Cc, then, having run out, every address on the message, which here was mine alone. The Reply-To now goes in that chain, one step before the last: when no recipient but me is left and the message names a Reply-To that is not mine either, that address is who it is really from. Keeping it after the Cc is what leaves a message I did send alone -- somebody I actually wrote to still beats my own Reply-To, which is the case the existing guard was built for and its test still holds. No new strings.
This commit is contained in:
@@ -153,6 +153,30 @@ describe("a message of mine with nobody obvious to reply to", () => {
|
|||||||
const d = await draftFor({ ...MINE, to: [ME], cc: [] } as Email, "reply");
|
const d = await draftFor({ ...MINE, to: [ME], cc: [] } as Email, "reply");
|
||||||
expect(addrs(d.to)).toEqual([ME.email]);
|
expect(addrs(d.to)).toEqual([ME.email]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("answers the Reply-To rather than my own desk when nobody else is on it", async () => {
|
||||||
|
/*
|
||||||
|
* A contact form: the site mails itself, From and To both its own address,
|
||||||
|
* and the person who filled the form in is in Reply-To. From alone makes
|
||||||
|
* this look like mine, and the fallback used to reply to me (#415).
|
||||||
|
*/
|
||||||
|
const form = { ...MINE, to: [ME], cc: [], replyTo: [{ name: "Michael", email: "[email protected]" }] } as Email;
|
||||||
|
const d = await draftFor(form, "reply");
|
||||||
|
expect(addrs(d.to)).toEqual(["[email protected]"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does the same on a reply all, without cc-ing myself", async () => {
|
||||||
|
const form = { ...MINE, to: [ME], cc: [], replyTo: [{ name: "Michael", email: "[email protected]" }] } as Email;
|
||||||
|
const d = await draftFor(form, "replyAll");
|
||||||
|
expect(addrs(d.to)).toEqual(["[email protected]"]);
|
||||||
|
expect(d.cc).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still prefers somebody I actually wrote to over my own Reply-To", async () => {
|
||||||
|
// The Cc is a person; the Reply-To is where answers to me belong.
|
||||||
|
const d = await draftFor({ ...MINE, to: [ME], replyTo: [{ name: null, email: "[email protected]" }] } as Email, "reply");
|
||||||
|
expect(addrs(d.to)).toEqual([BOB.email]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("forwarding", () => {
|
describe("forwarding", () => {
|
||||||
|
|||||||
@@ -410,6 +410,19 @@ export const useCompose = create<ComposeState>((set, get) => ({
|
|||||||
// Addressed only to myself, or only in Cc: there is still somebody this
|
// Addressed only to myself, or only in Cc: there is still somebody this
|
||||||
// is a reply to, and an empty To is not it.
|
// is a reply to, and an empty To is not it.
|
||||||
if (!to.length) { to = cc.length ? cc : withoutOwn(full.cc ?? []); cc = []; }
|
if (!to.length) { to = cc.length ? cc : withoutOwn(full.cc ?? []); cc = []; }
|
||||||
|
/*
|
||||||
|
* Nobody but me on the message, and a Reply-To pointing somewhere that
|
||||||
|
* is not mine: that address is who this is really from.
|
||||||
|
*
|
||||||
|
* A contact form is the shape of it -- From and To are both the site's
|
||||||
|
* own mailbox, and the person who filled the form in is in Reply-To.
|
||||||
|
* The address test above calls that mine, correctly as far as it goes,
|
||||||
|
* and the fallback then addressed the reply to my own desk (#415).
|
||||||
|
*
|
||||||
|
* After the Cc, not before it: a message I really did send carries my
|
||||||
|
* own Reply-To, and somebody I actually wrote to beats it.
|
||||||
|
*/
|
||||||
|
if (!to.length) to = withoutOwn(full.replyTo ?? []);
|
||||||
if (!to.length) to = uniqueAddresses([...(full.to ?? []), ...(full.cc ?? [])]);
|
if (!to.length) to = uniqueAddresses([...(full.to ?? []), ...(full.cc ?? [])]);
|
||||||
} else {
|
} else {
|
||||||
to = uniqueAddresses(full.replyTo?.length ? full.replyTo : (full.from ?? []));
|
to = uniqueAddresses(full.replyTo?.length ? full.replyTo : (full.from ?? []));
|
||||||
|
|||||||
Reference in New Issue
Block a user