diff --git a/app/company-settings-preview/page.tsx b/app/company-settings-preview/page.tsx index e0b03c6..e9d4599 100644 --- a/app/company-settings-preview/page.tsx +++ b/app/company-settings-preview/page.tsx @@ -21,6 +21,8 @@ const FALLBACK: CompanySettings = { sellerCity: "", sellerCountry: "", sellerEmail: "", + emailFromName: null, + emailFromAddress: null, vatId: "", taxRatePercent: 19, kleinunternehmer: false, diff --git a/app/lib/alertAdmin.ts b/app/lib/alertAdmin.ts index fea5caf..837e5b7 100644 --- a/app/lib/alertAdmin.ts +++ b/app/lib/alertAdmin.ts @@ -40,10 +40,10 @@ export async function sendVerificationEmail(to: string, firstName: string, token const url = `https://einfach-produktiv.mk360.de/api/account/verify-email?token=${token}`; const seller = await getSellerForInvoice(); await transport.sendMail({ - // See orderEmail.ts's own comment on why only the display name is - // dynamic — the address stays admin@mk360.de until sellerEmail's domain - // is confirmed SPF-authorized on the Hostinger account. - from: `"${seller?.sellerName ?? "einfach produktiv"}" `, + // See orderEmail.ts's own comment — From now matches sellerEmail + // itself since the SMTP account moved to a mailbox on that domain, + // and emailFromName/emailFromAddress let an admin override both. + from: `"${seller?.emailFromName || seller?.sellerName || "Björn"}" <${seller?.emailFromAddress || seller?.sellerEmail || "hallo@einfach-produktiv.com"}>`, replyTo: seller?.sellerEmail || undefined, to, subject: "Bitte bestätige deine E-Mail-Adresse", diff --git a/app/lib/orderEmail.ts b/app/lib/orderEmail.ts index a6bc72d..8e6044a 100644 --- a/app/lib/orderEmail.ts +++ b/app/lib/orderEmail.ts @@ -129,12 +129,16 @@ export async function sendOrderConfirmationEmail(order: OrderConfirmationEmailDa } await transport.sendMail({ - // Display name only, not the address — see the memory note on why the - // envelope stays admin@mk360.de (that's the domain the Hostinger SMTP - // account is actually authorized for; sellerEmail's domain isn't - // confirmed SPF-authorized on it yet). Reply-To is what actually routes - // a customer's reply to the seller, regardless of the From address. - from: `"${seller?.sellerName ?? "einfach produktiv"}" `, + // SPF confirmed 2026-07-29 for einfach-produktiv.com, and the SMTP + // account itself switched to a mailbox on that domain — see the + // backend's sellerInfo.ts buildFromHeader() comment for why both had + // to move together (Hostinger's relay rejects a From address the + // authenticated mailbox doesn't own). Reply-To stays set too, though + // now redundant with From itself pointing at sellerEmail. + // emailFromName/emailFromAddress (company-settings) are the + // admin-editable override, same fallback chain as the backend's + // buildFromHeader(). + from: `"${seller?.emailFromName || seller?.sellerName || "Björn"}" <${seller?.emailFromAddress || seller?.sellerEmail || "hallo@einfach-produktiv.com"}>`, replyTo: seller?.sellerEmail || undefined, to: customerEmail, subject: template.subject, diff --git a/app/lib/payload.ts b/app/lib/payload.ts index e597619..271ded9 100644 --- a/app/lib/payload.ts +++ b/app/lib/payload.ts @@ -878,6 +878,12 @@ export type CompanySettings = { sellerCity: string; sellerCountry: string; sellerEmail: string; + // Admin-editable override for outgoing mail's "Von"-Feld (company-settings + // "Adresse & Kontakt" tab, added 2026-07-29 alongside the SPF/SMTP-account + // switch to einfach-produktiv.com) — falls back to sellerName/sellerEmail + // when empty, see orderEmail.ts/alertAdmin.ts's own comments. + emailFromName: string | null; + emailFromAddress: string | null; vatId: string; taxRatePercent: number; // Kleinunternehmerregelung (§19 UStG) — when true, checkout forces every