fix(email): use tia@tia.manohargupta.com + auto-fallback to shared domain
- Primary sender: tia@tia.manohargupta.com (verified subdomain in Resend) - sendWithFallback() retries with onboarding@resend.dev if Resend rejects the primary domain (covers the window while SPF is still propagating) - Both sendFamilyInviteEmail() and sendVerificationEmail() use the fallback Update EMAIL_FROM in Dokploy to: Tia <tia@tia.manohargupta.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8a3da6a5a6
commit
31b4a9480a
1 changed files with 22 additions and 4 deletions
|
|
@ -1,10 +1,28 @@
|
||||||
import { Resend } from "resend";
|
import { Resend } from "resend";
|
||||||
|
|
||||||
const RESEND_API_KEY = process.env.RESEND_API_KEY;
|
const RESEND_API_KEY = process.env.RESEND_API_KEY;
|
||||||
// Falls back to Resend's shared test domain if EMAIL_FROM env var not set or domain not verified yet
|
// Primary: verified subdomain (set EMAIL_FROM=Tia <tia@tia.manohargupta.com> in Dokploy)
|
||||||
const EMAIL_FROM = process.env.EMAIL_FROM || "Tia <onboarding@resend.dev>";
|
// Fallback: Resend shared domain — works without domain verification
|
||||||
|
const EMAIL_FROM = process.env.EMAIL_FROM || "Tia <tia@tia.manohargupta.com>";
|
||||||
|
const EMAIL_FROM_FALLBACK = "Tia <onboarding@resend.dev>";
|
||||||
const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com";
|
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<Resend["emails"]["send"]>[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. */
|
/** Sends a family invite email, or logs the link in dev. */
|
||||||
export async function sendFamilyInviteEmail(opts: {
|
export async function sendFamilyInviteEmail(opts: {
|
||||||
to: string;
|
to: string;
|
||||||
|
|
@ -24,7 +42,7 @@ export async function sendFamilyInviteEmail(opts: {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resend = new Resend(RESEND_API_KEY);
|
const resend = new Resend(RESEND_API_KEY);
|
||||||
await resend.emails.send({
|
await sendWithFallback(resend, {
|
||||||
from: EMAIL_FROM,
|
from: EMAIL_FROM,
|
||||||
to,
|
to,
|
||||||
subject: `${inviterName} invited you to join their family on Tia 🍼`,
|
subject: `${inviterName} invited you to join their family on Tia 🍼`,
|
||||||
|
|
@ -63,7 +81,7 @@ export async function sendVerificationEmail(email: string, token: string, userId
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resend = new Resend(RESEND_API_KEY);
|
const resend = new Resend(RESEND_API_KEY);
|
||||||
await resend.emails.send({
|
await sendWithFallback(resend, {
|
||||||
from: EMAIL_FROM,
|
from: EMAIL_FROM,
|
||||||
to: email,
|
to: email,
|
||||||
subject: "Verify your Tia email",
|
subject: "Verify your Tia email",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue