diff --git a/components/email/__tests__/composer-send-pipeline.test.tsx b/components/email/__tests__/composer-send-pipeline.test.tsx index 075421c0e..ac68f45e5 100644 --- a/components/email/__tests__/composer-send-pipeline.test.tsx +++ b/components/email/__tests__/composer-send-pipeline.test.tsx @@ -3,6 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import React from 'react'; import { EmailComposer } from '../email-composer'; import { registerOutgoingFinalizer, registerPreSendCheck, resetSendPipeline } from '@/lib/outgoing/send-pipeline'; +import { composerHandle } from '@/lib/plugin-sandbox/composer-registry'; // ─── Heavy component mocks (mirrors composer-reopened-draft-signature.test.tsx) ─ @@ -231,6 +232,16 @@ describe('composer send pipeline', () => { })]); }); + it('names the composer plugins know it by, for onAfterEmailSend', async () => { + let open = false; + const onSend = vi.fn((data: { composerId?: string }) => { open = !!composerHandle(data.composerId); }); + render(); + clickSend(); + await waitFor(() => expect(onSend).toHaveBeenCalledTimes(1)); + expect(onSend.mock.calls[0][0]).toEqual(expect.objectContaining({ composerId: expect.any(String) })); + expect(open).toBe(true); + }); + it('sends nothing when a check says no, and sends after it says yes', async () => { let allow = false; const check = vi.fn(() => allow); diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index b0d46d740..5d7bfe0cd 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -296,6 +296,8 @@ interface EmailComposerProps { requireTls?: boolean; /** Importance / X-Priority; absent for normal (#970). */ priority?: MessagePriority; + /** The id plugins know this composer by, for onAfterEmailSend. */ + composerId?: string; }) => void | false | Promise; onScheduledSendCreated?: () => void | Promise; onClose?: () => void; @@ -3679,6 +3681,7 @@ export function EmailComposer({ requireTls: requireTls || undefined, priority: priority !== 'normal' ? priority : undefined, delayedUntil: effectiveDelayedUntil, + composerId: pluginComposerIdRef.current ?? undefined, }); // Not when nothing went: no host, or one that sent nothing. if (draftElsewhere && onSend && outcome !== false) await removeDraftVersion(finalDraftId!, draftLogin, draftAccountAtSend); diff --git a/components/mail/__tests__/after-send-hook.test.tsx b/components/mail/__tests__/after-send-hook.test.tsx index 62a03e54a..e71b1006a 100644 --- a/components/mail/__tests__/after-send-hook.test.tsx +++ b/components/mail/__tests__/after-send-hook.test.tsx @@ -25,7 +25,7 @@ const sendData = vi.hoisted(() => ({ delayedUntil: undefined as string | undefin vi.mock('@/components/email/email-composer', () => ({ EmailComposer: ({ onSend }: { onSend?: (data: unknown) => Promise }) => (