import { Resend } from "resend"; const RESEND_API_KEY = process.env.RESEND_API_KEY; // Primary: verified subdomain (set EMAIL_FROM=Tia in Dokploy) // Fallback: Resend shared domain — works without domain verification const EMAIL_FROM = process.env.EMAIL_FROM || "Tia "; const EMAIL_FROM_FALLBACK = "Tia "; const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com"; /** Send email with automatic fallback to shared domain if primary domain isn't verified yet */ async function sendWithFallback(resend: Resend, payload: Parameters[0]) { const result = await resend.emails.send(payload); // Resend returns { error } object rather than throwing for domain issues const err = (result as { error?: { message?: string; name?: string } }).error; if (err) { const msg = (err.message || err.name || "").toLowerCase(); if (msg.includes("domain") || msg.includes("verif") || msg.includes("sender")) { console.warn("[EMAIL-FALLBACK] Primary domain rejected, retrying with shared domain:", err.message); return await resend.emails.send({ ...payload, from: EMAIL_FROM_FALLBACK }); } throw new Error(err.message || "Resend error"); } return result; } /** Sends a family invite email, or logs the link in dev. */ export async function sendFamilyInviteEmail(opts: { to: string; inviterName: string; familyName: string; token: string; role: string; }) { const { to, inviterName, familyName, token, role } = opts; const link = `${APP_URL}/invite/${token}`; const roleLabel = role === "admin" ? "an admin" : "a caregiver"; if (!RESEND_API_KEY) { console.log(`[INVITE-LINK] to=${to} family=${familyName} link=${link}`); return; } try { const resend = new Resend(RESEND_API_KEY); await sendWithFallback(resend, { from: EMAIL_FROM, to, subject: `${inviterName} invited you to join their family on Tia 🍼`, html: `

You're invited! 🎉

${inviterName} has invited you to join ${familyName} on Tia as ${roleLabel}.

Tia helps families track feeds, sleep, growth, memories, and more — all in one place.

Accept Invitation

This link expires in 7 days. If you didn't expect this, you can safely ignore it.

`, }); console.log(`[INVITE-EMAIL-SENT] to=${to} family=${familyName}`); } catch (e) { console.error("[INVITE-EMAIL-FAILED]", e); } } /** Sends an account-verification email, or logs the link in dev. */ export async function sendVerificationEmail(email: string, token: string, userId: string) { const link = `${APP_URL}/api/auth/verify-email?token=${token}`; if (!RESEND_API_KEY) { // Dev fallback: no Resend key -> print the link so test accounts // can be verified straight from the server log. console.log(`[VERIFY-LINK] user=${userId} email=${email} link=${link}`); return; } try { const resend = new Resend(RESEND_API_KEY); await sendWithFallback(resend, { from: EMAIL_FROM, to: email, subject: "Verify your Tia email", html: `

Welcome to Tia

Confirm this email to activate your account. This link expires in 24 hours.

Verify Email

If you didn't create a Tia account, ignore this email.

`, }); console.log(`[VERIFY-EMAIL-SENT] user=${userId} email=${email}`); } catch (e) { console.error("[VERIFY-EMAIL-FAILED]", e); } }