diff --git a/app/(main)/[locale]/page.tsx b/app/(main)/[locale]/page.tsx index 714868fa..e25eecd5 100644 --- a/app/(main)/[locale]/page.tsx +++ b/app/(main)/[locale]/page.tsx @@ -61,6 +61,7 @@ import { Input } from "@/components/ui/input"; import { FilePreviewModal } from "@/components/files/file-preview-modal"; import { isFilePreviewable } from "@/lib/file-preview"; import { appendHtmlSignature, appendPlainTextSignature } from "@/lib/signature-utils"; +import { useSignatureStore } from "@/stores/signature-store"; import { computeReplyThreadingHeaders } from "@/lib/email-threading"; import { EML_IMPORT_ACCEPT, expandImportableEmails } from "@/lib/eml-import"; import { findDraftIdentityId, resolveReplyFrom, type ReplyFromResolution } from "@/lib/reply-identity"; @@ -2615,8 +2616,16 @@ export default function Home() { // Append signature from the sending identity (fall back to primary // when the reply-from lives on the same identity but a different alias). + // The signature store's reply signature takes precedence over the legacy + // identity signature, matching the composer's send path. + const signatureStore = useSignatureStore.getState(); + const replySigId = signatureStore.getIdentityReplySignatureId(sendingIdentity?.id ?? ''); + const replySig = replySigId ? signatureStore.getSignatureById(replySigId) : undefined; + const signatureSource = replySig + ? { htmlSignature: replySig.body, textSignature: replySig.plainText } + : sendingIdentity; const separator = useSettingsStore.getState().signatureSeparatorEnabled; - const finalBody = appendPlainTextSignature(body, sendingIdentity, { separator }); + const finalBody = appendPlainTextSignature(body, signatureSource, { separator }); // When the identity has an HTML signature, send a matching HTML body so the // signature keeps its formatting; appendPlainTextSignature would otherwise @@ -2627,8 +2636,8 @@ export default function Home() { .replace(//g, '>') .replace(/\n/g, '
'); - const finalHtmlBody = sendingIdentity?.htmlSignature?.trim() - ? appendHtmlSignature(`
${escapedBody}
`, sendingIdentity, { separator }) + const finalHtmlBody = signatureSource?.htmlSignature?.trim() + ? appendHtmlSignature(`
${escapedBody}
`, signatureSource, { separator }) : undefined; const originalEmailId = selectedEmail.id; diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index d765b80a..2e09bbe1 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -653,6 +653,15 @@ export function EmailComposer({ ? currentIdentity : primaryIdentity; + // The signature store (default/reply/per-identity) takes precedence over the + // legacy per-identity html/text signature. `selectedSignature` is resolved in + // resolveStoreSignatureId for the current mode (compose → default; reply/ + // forward → reply), so replies and forwards pick up the reply signature. + // Falls back to the legacy identity signature when no store signature is set. + const effectiveSignature = selectedSignature + ? { htmlSignature: selectedSignature.body, textSignature: selectedSignature.plainText } + : signatureIdentity; + // Hold the TipTap editor instance so we can swap the embedded signature // when the user switches identity in "above quote" mode without rebuilding // the whole body (which would lose user edits to the surrounding draft). @@ -1883,6 +1892,7 @@ export function EmailComposer({ // duplicate it. const signatureAlreadyInBody = shouldEmbedSignatureInNewMail || + (!plainTextMode && !!selectedSignature && mode === 'compose') || ((mode === 'reply' || mode === 'replyAll' || mode === 'forward') && signaturePosition === 'above_quote'); @@ -1890,11 +1900,11 @@ export function EmailComposer({ const buildSignatureHtml = (): string => { if (signatureAlreadyInBody) return ''; const sep = signatureSeparatorEnabled ? `

--
` : `

`; - if (signatureIdentity?.htmlSignature) { - return `${sep}${sanitizeSignatureHtml(signatureIdentity.htmlSignature)}`; + if (effectiveSignature?.htmlSignature) { + return `${sep}${sanitizeSignatureHtml(effectiveSignature.htmlSignature)}`; } - if (signatureIdentity?.textSignature) { - return `${sep}${signatureIdentity.textSignature.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
')}`; + if (effectiveSignature?.textSignature) { + return `${sep}${effectiveSignature.textSignature.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
')}`; } return ''; }; @@ -1907,8 +1917,8 @@ export function EmailComposer({ // In plain text mode, send text/plain only (no HTML body) const signatureOpts = { separator: signatureSeparatorEnabled }; const finalBody = plainTextMode - ? (signatureAlreadyInBody ? body : appendPlainTextSignature(body, signatureIdentity, signatureOpts)) - : (signatureAlreadyInBody ? htmlToPlainText(body) : appendPlainTextSignature(htmlToPlainText(body), signatureIdentity, signatureOpts)); + ? (signatureAlreadyInBody ? body : appendPlainTextSignature(body, effectiveSignature, signatureOpts)) + : (signatureAlreadyInBody ? htmlToPlainText(body) : appendPlainTextSignature(htmlToPlainText(body), effectiveSignature, signatureOpts)); const rewritten = plainTextMode ? null : rewriteInlineImages(body); const finalHtmlBody = plainTextMode