From 0ce61756b7842c0f7364ce14bf7ba4d6a58ba265 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Mon, 20 Apr 2026 13:48:38 +0100 Subject: [PATCH] feat(emails): warmer copy across invite, welcome, and event emails Friendlier tone + ghost emoji on invite/welcome subjects; invite templates now offer a reply-to-this-email fallback; tighten OIDC wiki sign-in and event registration confirmation copy. --- app/pages/admin/members/index.vue | 4 ++-- app/pages/admin/pre-registrants/index.vue | 6 ++++-- server/api/admin/members/invite.post.js | 4 ++-- .../api/admin/pre-registrants/invite.post.js | 2 +- server/routes/oidc/interaction/login.post.ts | 4 +--- server/utils/resend.js | 18 +++++++++--------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/pages/admin/members/index.vue b/app/pages/admin/members/index.vue index d5e4677..48ca472 100644 --- a/app/pages/admin/members/index.vue +++ b/app/pages/admin/members/index.vue @@ -522,14 +522,14 @@ const inviteResults = ref(null); const DEFAULT_INVITE_TEMPLATE = `Hi {name}, -You've been invited to Ghost Guild as a member of the {circle} circle. +You've been invited to Ghost Guild. Sign in here to get started: {loginLink} This link expires in 48 hours. After that, you can always request a new login link at https://ghostguild.org/login. -See you inside.`; +Reply to this email if you have any trouble!`; const inviteTemplate = ref(DEFAULT_INVITE_TEMPLATE); diff --git a/app/pages/admin/pre-registrants/index.vue b/app/pages/admin/pre-registrants/index.vue index b88ee23..3a62be5 100644 --- a/app/pages/admin/pre-registrants/index.vue +++ b/app/pages/admin/pre-registrants/index.vue @@ -247,9 +247,11 @@ Click below to accept your invitation, choose your circle, and set your contribu {acceptLink} -This link expires in 48 hours. If it expires, we can send you a new one. +This link expires in 48 hours. If it expires, we can send you a new one. Just reply to this email. -See you inside.`; +See you soon! + +– Ghost Guild`; const inviteTemplate = ref(DEFAULT_INVITE_TEMPLATE); diff --git a/server/api/admin/members/invite.post.js b/server/api/admin/members/invite.post.js index f2f2f0d..ebd866c 100644 --- a/server/api/admin/members/invite.post.js +++ b/server/api/admin/members/invite.post.js @@ -75,7 +75,7 @@ export default defineEventHandler(async (event) => { const { error: emailError } = await resend.emails.send({ from: 'Ghost Guild ', to: [member.email], - subject: "You're invited to Ghost Guild", + subject: "You're invited to Ghost Guild! 👻", text: emailText, html: emailHtml, }) @@ -102,7 +102,7 @@ export default defineEventHandler(async (event) => { logActivity(member._id, 'email_sent', { emailType: 'invite', - subject: "You're invited to Ghost Guild", + subject: "You're invited to Ghost Guild! 👻", body: emailText }) diff --git a/server/api/admin/pre-registrants/invite.post.js b/server/api/admin/pre-registrants/invite.post.js index 70eef7c..3d16b88 100644 --- a/server/api/admin/pre-registrants/invite.post.js +++ b/server/api/admin/pre-registrants/invite.post.js @@ -66,7 +66,7 @@ export default defineEventHandler(async (event) => { const { error: emailError } = await resend.emails.send({ from: 'Ghost Guild ', to: [preReg.email], - subject: "You're invited to Ghost Guild", + subject: "You're invited to Ghost Guild! 👻", text: emailText, html: emailHtml, }) diff --git a/server/routes/oidc/interaction/login.post.ts b/server/routes/oidc/interaction/login.post.ts index a9dd894..0799a27 100644 --- a/server/routes/oidc/interaction/login.post.ts +++ b/server/routes/oidc/interaction/login.post.ts @@ -50,9 +50,7 @@ export default defineEventHandler(async (event) => { from: "Ghost Guild ", to: email, subject: "Sign in to Ghost Guild Wiki", - text: `Sign in to the Ghost Guild Wiki - -Use this link to sign in: + text: `Use this link to sign in to the Ghost Guild Wiki: ${baseUrl}/oidc/interaction/verify?token=${token} diff --git a/server/utils/resend.js b/server/utils/resend.js index 734bac5..24b2356 100644 --- a/server/utils/resend.js +++ b/server/utils/resend.js @@ -62,9 +62,9 @@ Paid: $${registration.amountPaid.toFixed(2)} CAD`; from: "Ghost Guild ", to: [registration.email], subject: `You're registered for ${eventData.title}`, - text: `Hi ${registration.name}, + text: `Hi ${registration.name}! -You're registered for ${eventData.title}. +You're now registered for ${eventData.title}. Date: ${formatDate(eventData.startDate)} Time: ${formatTime(eventData.startDate, eventData.endDate)} @@ -72,7 +72,9 @@ Location: ${eventData.location} ${eventData.description ? `\n${eventData.description}\n` : ""}${ticketSection}${signInSection} View event: ${eventUrl} -To cancel, visit the event page and click "Cancel Registration."`, +To cancel, visit the event page and click "Cancel Registration." + +We look forward to seeing you there!`, }); if (error) { @@ -272,17 +274,15 @@ export async function sendWelcomeEmail(member) { const { data, error } = await resend.emails.send({ from: "Ghost Guild ", to: [member.email], - subject: "Welcome to Ghost Guild", - text: `Hi ${member.name}, + subject: "Welcome to Ghost Guild! 👻", + text: `Hi ${member.name}! Welcome to Ghost Guild! You're now part of the ${member.circle} circle. -Sign in to your dashboard: +Sign in to your dashboard to get started: ${baseUrl}/member/dashboard -If you have questions, reach out on Slack or reply to this email. - -— Ghost Guild`, +If you have questions, reach out to jennie + eileen on Slack or reply to this email.`, }); if (error) {