d7e7928dfc
Customer replies to order-confirmation and resend-verification mail now route to the seller's real address via Reply-To, and the From display name reflects sellerName — but the From address itself stays admin@mk360.de since sellerEmail's domain isn't confirmed SPF-authorized on the Hostinger account yet (see the "SMTP From address pending SPF" memory note for the follow-up). Also cleans up README references left over from the previous footer rewrite (stale "company line" wording, a dangling cross-reference to a renamed section). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
53 lines
2.7 KiB
TypeScript
53 lines
2.7 KiB
TypeScript
import { transport } from "./mailer";
|
|
import { buildLegalFooterLines, renderVerificationEmailHtml } from "./emailTemplates";
|
|
import { getSellerForInvoice } from "./invoiceData";
|
|
|
|
// Fire-and-forget by design — callers should not await this in a way that
|
|
// blocks or fails the actual error response the customer sees. Wrap
|
|
// everything in its own try/catch so a broken mail relay never becomes a
|
|
// second, worse failure on top of the one being reported. Internal-only
|
|
// (sent to admin@mk360.de, this business's own inbox), but still carries
|
|
// the plain-text Anbieterkennzeichnung for consistency with every other
|
|
// email this app sends — see buildLegalFooterLines() in emailTemplates.ts.
|
|
export function sendCriticalAlert(subject: string, details: Record<string, unknown>): void {
|
|
getSellerForInvoice()
|
|
.catch(() => null)
|
|
.then((seller) => {
|
|
const footer = buildLegalFooterLines(seller).join("\n");
|
|
return transport.sendMail({
|
|
from: '"einfach produktiv Alerts" <admin@mk360.de>',
|
|
to: "admin@mk360.de",
|
|
subject: `[einfach produktiv] ${subject}`,
|
|
text: `${JSON.stringify(details, null, 2)}\n\n---\n${footer}`,
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
console.error("sendCriticalAlert: failed to send alert email", err);
|
|
});
|
|
}
|
|
|
|
// The *initial* verification email (on registration) is sent by Payload
|
|
// itself, via Customers.ts's own afterChange hook — that one fires
|
|
// automatically on create and needs no separate wiring. This one is only
|
|
// for the "erneut senden" resend path (app/api/account/resend-verification/
|
|
// route.ts), which updates the token via the customer's own session
|
|
// (app/lib/customerAuth.ts's resendVerificationEmail) but has no Payload
|
|
// hook to piggyback on for a plain update, so it sends directly instead —
|
|
// same Hostinger transport as the alert above, and the same branded
|
|
// emailShell()/legal-footer template as every other email (see
|
|
// renderVerificationEmailHtml in emailTemplates.ts).
|
|
export async function sendVerificationEmail(to: string, firstName: string, token: string): Promise<void> {
|
|
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"}" <admin@mk360.de>`,
|
|
replyTo: seller?.sellerEmail || undefined,
|
|
to,
|
|
subject: "Bitte bestätige deine E-Mail-Adresse",
|
|
html: renderVerificationEmailHtml(firstName, url, seller),
|
|
});
|
|
}
|