From 2a769c2b0a912b6c840dc73a3c064d657037fa7d Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Tue, 5 May 2026 20:04:00 +0200 Subject: [PATCH] feat: run onBeforeEmailSend hook before send, expose fromEmail on OutgoingEmail --- components/email/email-composer.tsx | 21 +++++++++++++++++++++ lib/plugin-types.ts | 2 ++ 2 files changed, 23 insertions(+) diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index 083b2fc6..7f1b093b 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -980,6 +980,26 @@ export function EmailComposer({ const inlineAttachments = rewritten?.attachments ?? []; try { + // Let plugins veto the send (external-recipient warning, mistyped-domain + // guards, etc.). Returning false from any handler aborts before either + // the S/MIME or standard JMAP path runs. + const sendablePreview: OutgoingEmail = { + to: toAddresses, + cc: ccAddresses, + bcc: bccAddresses, + subject, + htmlBody: finalHtmlBody || '', + textBody: finalBody, + identityId: currentIdentity?.id || '', + fromEmail, + attachments: attachments + .filter(att => att.blobId && !att.uploading && !att.error) + .map(a => ({ name: a.name, type: a.type || 'application/octet-stream', size: a.size })), + inReplyTo: threadingHeaders?.inReplyTo?.[0], + }; + const sendAllowed = await emailHooks.onBeforeEmailSend.intercept(sendablePreview); + if (!sendAllowed) return; + // S/MIME send pipeline: build raw MIME → sign → encrypt → sendRawEmail if ((smimeSign_ || smimeEncrypt_) && client && currentIdentity?.id) { // 1. Resolve S/MIME key @@ -1115,6 +1135,7 @@ export function EmailComposer({ htmlBody: finalHtmlBody || '', textBody: finalBody, identityId: currentIdentity?.id || '', + fromEmail, attachments: uploadedAttachments.map(a => ({ name: a.name, type: a.type, size: a.size })), inReplyTo: threadingHeaders?.inReplyTo?.[0], }; diff --git a/lib/plugin-types.ts b/lib/plugin-types.ts index 365778c2..995d1e78 100644 --- a/lib/plugin-types.ts +++ b/lib/plugin-types.ts @@ -541,6 +541,8 @@ export interface OutgoingEmail { htmlBody: string; textBody: string; identityId: string; + /** Sender email derived from the active identity (incl. sub-address tag, when set) */ + fromEmail?: string; attachments: { name: string; type: string; size: number }[]; /** Original message id when this is a reply or forward */ inReplyTo?: string;