feat: run onBeforeEmailSend hook before send, expose fromEmail on OutgoingEmail

This commit is contained in:
Linus Rath
2026-05-05 20:04:00 +02:00
parent 28054c81ea
commit 2a769c2b0a
2 changed files with 23 additions and 0 deletions
+21
View File
@@ -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],
};
+2
View File
@@ -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;