fix: remove the unsent copy from Drafts when a send fails

This commit is contained in:
Linus Rath
2026-10-11 19:09:11 +02:00
parent 1614cab78b
commit fa7e29f980
3 changed files with 52 additions and 2 deletions
+3 -2
View File
@@ -208,8 +208,9 @@ describe('draft replace lifecycle (#849)', () => {
'draft-old-1',
)).rejects.toThrow();
// Only the unsent copy may go; the user's draft stays for a retry.
for (const set of emailSetCalls(captured)) {
expect(set.destroy).toBeUndefined();
expect(set.destroy ?? []).not.toContain('draft-old-1');
}
});
@@ -242,7 +243,7 @@ describe('compose failure recovery', () => {
// Only the missing submission is unconfirmed; a method error is a plain failure.
options.missingSubmission ? SendUnconfirmedError : Error,
);
expect(emailSetCalls(captured).some(call => call.destroy)).toBe(false);
expect(emailSetCalls(captured).some(call => (call.destroy as string[] | undefined)?.includes('old-draft'))).toBe(false);
});
it('accepts empty notCreated maps as success', async () => {
const client = createClient(); mockFlow({ emptyErrors: true });
@@ -225,6 +225,16 @@ describe('JMAPClient.sendEmail refused recipients (#1123)', () => {
await expect(send(createClient())).rejects.toThrow('Sending is disabled.');
});
it('removes the unsent copy from Drafts when the submission is refused', async () => {
// The copy was created in Drafts next to the user's own draft. Left
// there, every failed attempt added a duplicate that outlived the send.
const { destroyed } = mockServer({ refuseSubmission: true });
await expect(send(createClient(), { draftId: 'draft-1' })).rejects.toThrow('Sending is disabled.');
expect(destroyed).toEqual(['email-9']);
});
it('treats a server that cannot answer the read-back as a plain success', async () => {
mockServer({ noSubmissionGet: true });
@@ -288,6 +298,14 @@ describe('JMAPClient raw sends refused recipients (#1123)', () => {
expect(destroyed).toEqual(['email-9']);
});
it('sendRawEmail removes the imported copy when the submission is refused', async () => {
const { destroyed } = mockServer({ refuseSubmission: true });
await expect(rawClient().sendRawEmail(new Blob(['raw']), 'identity-1', 'mb-sent', 'mb-drafts'))
.rejects.toThrow('Sending is disabled.');
expect(destroyed).toEqual(['email-9']);
});
it('submitRawEmail fails when every recipient was refused', async () => {
const { requests } = mockServer({
deliveryStatus: { 'gone@example.com': { delivered: 'no', smtpReply: MAILBOX_GONE, displayed: 'unknown' } },