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