feat: remove defer (#243)
* working on moving the email logic to the backend * Moved nodemailer to the backend * uninstall defer * updated relative import path in tsconfig * working on the zod validation * Merge branch 'main' into send-email * fixed the zod import issue * fixed the zod import issue * updated the env example files * docs: update README.md (#249) * fix: handle catex error * chore: remove fly.io github action * Update README.md Updated the Readme to reflect changes made to the emailing flow --------- Co-authored-by: Rotimi Best <[email protected]> * chore: wrapp up email sending --------- Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
import { defer } from '@defer/client';
|
||||
|
||||
import { withEmailTemplate } from '../lib/utils/services/notification/template';
|
||||
import { getTransporter } from '../lib/utils/services/notification/send';
|
||||
|
||||
const sendEmail = async ({
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
content,
|
||||
isPersonalEmail,
|
||||
replyTo
|
||||
}: {
|
||||
from?: string;
|
||||
to: string;
|
||||
subject: string;
|
||||
content: string;
|
||||
isPersonalEmail?: boolean;
|
||||
replyTo?: string;
|
||||
}) => {
|
||||
try {
|
||||
const transporter = await getTransporter(isPersonalEmail);
|
||||
|
||||
if (!transporter) {
|
||||
return;
|
||||
}
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: from || '"Best from ClassroomIO" <[email protected]>', // sender address
|
||||
to, // list of receivers
|
||||
subject, // Subject line
|
||||
replyTo,
|
||||
html: withEmailTemplate(content) // html body
|
||||
});
|
||||
|
||||
console.log('Message sent: %s', info.messageId);
|
||||
|
||||
return info;
|
||||
} catch (error) {
|
||||
console.error({ error });
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
export default defer(sendEmail);
|
||||
@@ -1,42 +0,0 @@
|
||||
import { defer } from '@defer/client';
|
||||
|
||||
import { withEmailTemplate } from '../lib/utils/services/notification/template';
|
||||
import { getTransporter } from '../lib/utils/services/notification/send';
|
||||
|
||||
// Send multiple emails
|
||||
const sendEmails = async (
|
||||
emailParams: {
|
||||
from?: string;
|
||||
to: string;
|
||||
subject: string;
|
||||
content: string;
|
||||
isPersonalEmail?: boolean;
|
||||
replyTo?: string;
|
||||
}[]
|
||||
) => {
|
||||
for (const emailParam of emailParams) {
|
||||
const { from, to, subject, content, isPersonalEmail, replyTo } = emailParam;
|
||||
|
||||
try {
|
||||
const transporter = await getTransporter(isPersonalEmail);
|
||||
|
||||
if (!transporter) {
|
||||
return;
|
||||
}
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: from || '"Best from ClassroomIO" <[email protected]>', // sender address
|
||||
to, // list of receivers
|
||||
subject, // Subject line
|
||||
replyTo,
|
||||
html: withEmailTemplate(content) // html body
|
||||
});
|
||||
|
||||
console.log('Message sent: %s', info.messageId);
|
||||
} catch (error) {
|
||||
console.error({ error });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default defer(sendEmails);
|
||||
@@ -25,7 +25,6 @@
|
||||
triggerSendEmail
|
||||
} from '$lib/utils/services/notification/notification';
|
||||
import { lesson } from '../store/lessons';
|
||||
import { onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let preview: false;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { PUBLIC_SERVER_URL } from '$env/static/public';
|
||||
|
||||
const sendEmail = async (
|
||||
emailDataArray: {
|
||||
from?: string;
|
||||
to: any;
|
||||
subject: string;
|
||||
content: any;
|
||||
replyTo?: any;
|
||||
isPersonalEmail?: boolean;
|
||||
}[]
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(`${PUBLIC_SERVER_URL}/sendEmail`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(emailDataArray)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.log('Failed to send emails');
|
||||
return;
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
console.log('Emails sent successfully:', responseData);
|
||||
return responseData;
|
||||
} catch (error) {
|
||||
console.error('Error sending emails:', error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
export default sendEmail;
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -24,12 +24,16 @@ export async function POST({ request }) {
|
||||
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
}
|
||||
|
||||
await sendEmail({
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `[Submitted]: ${exerciseTitle}`,
|
||||
content
|
||||
});
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `[Submitted]: ${exerciseTitle}`,
|
||||
content
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import { getFeedForNotification } from '$lib/utils/services/newsfeed/index';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmails from '$defer/sendEmails';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -13,20 +12,25 @@ const sendEmailNotification = async (feedId: string, authorId: string, comment?:
|
||||
const postLink = `https://${feed.org.siteName}.classroomio.com/courses/${feed.courseId}?feedId=${feed.id}`;
|
||||
|
||||
if (comment) {
|
||||
// send only to teacher
|
||||
await sendEmail({
|
||||
from: `"${feed.org.name} - ClassroomIO" <[email protected]>`,
|
||||
to: feed.teacherEmail,
|
||||
subject: `[${feed.courseTitle}] - News feed comment`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${feed.org.name} - ClassroomIO" <[email protected]>`,
|
||||
to: feed.teacherEmail,
|
||||
subject: `[${feed.courseTitle}] - News feed comment`,
|
||||
content: `
|
||||
<p>A student left you a comment on your newsfeed post</p>
|
||||
|
||||
<div style="font-style: italic; margin-top: 10px;">${comment}</div>
|
||||
<div>
|
||||
<a class="button" href="${postLink}">View comment</a>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
`,
|
||||
isPersonalEmail: false,
|
||||
replyTo: '[email protected]'
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
// dont continue
|
||||
return;
|
||||
@@ -37,7 +41,7 @@ const sendEmailNotification = async (feedId: string, authorId: string, comment?:
|
||||
}
|
||||
|
||||
// else send to everyone except the author of the post
|
||||
const emails = feed.courseMembers.map((member) => ({
|
||||
const emailsData = feed.courseMembers.map((member) => ({
|
||||
from: `"${feed.org.name} - ClassroomIO" <[email protected]>`,
|
||||
to: member.email,
|
||||
replyTo: feed.teacherEmail,
|
||||
@@ -53,8 +57,8 @@ const sendEmailNotification = async (feedId: string, authorId: string, comment?:
|
||||
}));
|
||||
console.log('Sending emails to all students', feed.courseMembers.length);
|
||||
|
||||
// This is the defer function with a loop
|
||||
await sendEmails(emails);
|
||||
// This is the email sending function with a loop
|
||||
await sendEmail(emailsData);
|
||||
};
|
||||
|
||||
export async function POST({ request }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
// import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
// const supabase = getSupabase();
|
||||
|
||||
@@ -32,19 +32,23 @@ export async function POST({ request }) {
|
||||
// return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
// }
|
||||
|
||||
await sendEmail({
|
||||
from: `"${orgName} - ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
replyTo: teacherEmail,
|
||||
subject: `[${courseName}] One more step left`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${orgName} - ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
replyTo: teacherEmail,
|
||||
subject: `[${courseName}] One more step left`,
|
||||
content: `
|
||||
<p>Hi ${studentFullname},</p>
|
||||
<p>You are one step closer to joining: <strong>${courseName}</strong></p>
|
||||
<p>Please send your proof of payment to: <strong>${teacherEmail}</strong>, in order to join the course.</p>
|
||||
<p>Talk to you soon and see you in class.</p>
|
||||
<p>${orgName}</p>
|
||||
`
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -26,11 +26,12 @@ export async function POST({ request }) {
|
||||
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
}
|
||||
|
||||
await sendEmail({
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `${orgName} - Welcome to Class 🎉`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `${orgName} - Welcome to Class 🎉`,
|
||||
content: `
|
||||
<p>Hi there,</p>
|
||||
<p>Congratulations 🎉, you’ve successfully joined: <strong>${courseName}</strong></p>
|
||||
<p>Everything has been set up for you to have an amazing learning experience.</p>
|
||||
@@ -38,7 +39,9 @@ export async function POST({ request }) {
|
||||
<p>Cheers,</p>
|
||||
<p>${orgName}</p>
|
||||
`
|
||||
});
|
||||
}
|
||||
];
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -24,12 +24,16 @@ export async function POST({ request }) {
|
||||
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
}
|
||||
|
||||
await sendEmail({
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: 'Submission Update',
|
||||
content
|
||||
});
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: 'Submission Update',
|
||||
content
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
// import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
// const supabase = getSupabase();
|
||||
|
||||
@@ -31,11 +31,12 @@ export async function POST({ request }) {
|
||||
// return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
// }
|
||||
|
||||
await sendEmail({
|
||||
from: `ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
subject: `[${courseName}] Request to Join Course!`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
subject: `[${courseName}] Request to Join Course!`,
|
||||
content: `
|
||||
<p>Hi amazing tutor,</p>
|
||||
<p> A new student has requested to join a course you are teaching: “${courseName}"</p>
|
||||
<p style="font: bold;">Student details</p>
|
||||
@@ -44,7 +45,9 @@ export async function POST({ request }) {
|
||||
Email: ${studentEmail}
|
||||
</p>
|
||||
`
|
||||
});
|
||||
}
|
||||
];
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -25,18 +25,22 @@ export async function POST({ request }) {
|
||||
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
}
|
||||
|
||||
await sendEmail({
|
||||
from: `"ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
subject: `[${courseName}] You've got a new student 🎉!`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `"ClassroomIO" <[email protected]>`,
|
||||
to,
|
||||
subject: `[${courseName}] You've got a new student 🎉!`,
|
||||
content: `
|
||||
<p>Hi amazing tutor,</p>
|
||||
<p>Congratulations 🎉, a new student has joined a course you are teaching: ${courseName}</p>
|
||||
<p>We hope they have a great experience learning from the best (YOU).</p>
|
||||
<p>If you run into any issues, please don’t fail to reach out to us, we’d love to make your teaching
|
||||
experience as easy as possible.</p>
|
||||
`
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -28,11 +28,12 @@ export async function POST({ request }) {
|
||||
const origin = request.headers.get('origin');
|
||||
const inviteLink = `${origin}/org/${orgSiteName}/courses`;
|
||||
|
||||
await sendEmail({
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `You have been invited to a course in ${orgName}!`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
from: `"${orgName} (via ClassroomIO.com)" <[email protected]>`,
|
||||
to,
|
||||
subject: `You have been invited to a course in ${orgName}!`,
|
||||
content: `
|
||||
<p>Hey ${name},</p>
|
||||
<p> You have been given access to teach a course by ${orgName}</p>
|
||||
<p>The course is titled: ${courseName}</p>
|
||||
@@ -40,7 +41,10 @@ export async function POST({ request }) {
|
||||
<a class="button" href="${inviteLink}">Open Dashboard</a>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -42,18 +42,21 @@ export async function POST({ request }) {
|
||||
const inviteLink = `${origin}/invite/t/${encodeURIComponent(btoa(inviteData))}`;
|
||||
console.log('inviteData', inviteData);
|
||||
|
||||
await sendEmail({
|
||||
to: email,
|
||||
subject: `Join ${name} on ClassroomIO 😃`,
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
to: email,
|
||||
subject: `Join ${name} on ClassroomIO 😃`,
|
||||
content: `
|
||||
<p>Hey there,</p>
|
||||
<p> You have been invited to join ${name} on ClassroomIO 🎉🎉🎉.</p>
|
||||
<div>
|
||||
<a class="button" href="${inviteLink}">Accept Invitation</a>
|
||||
</div>
|
||||
`,
|
||||
isPersonalEmail: true
|
||||
});
|
||||
isPersonalEmail: true
|
||||
}
|
||||
];
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -35,18 +35,22 @@ export async function POST({ request }) {
|
||||
btoa(verificationData)
|
||||
)}`;
|
||||
|
||||
await sendEmail({
|
||||
to,
|
||||
subject: '[ClassroomIO]: Verify your email',
|
||||
content: `
|
||||
<p>Thank you for signing up</p>
|
||||
<p>To verify your email, please click the <strong>Verify</strong> button below </p>
|
||||
<div>
|
||||
<a class="button" href="${verificationLink}">Verify</a>
|
||||
</div>
|
||||
`,
|
||||
isPersonalEmail: true
|
||||
});
|
||||
const emailData = [
|
||||
{
|
||||
to,
|
||||
subject: '[ClassroomIO]: Verify your email',
|
||||
content: `
|
||||
<p>Thank you for signing up</p>
|
||||
<p>To verify your email, please click the <strong>Verify</strong> button below </p>
|
||||
<div>
|
||||
<a class="button" href="${verificationLink}">Verify</a>
|
||||
</div>
|
||||
`,
|
||||
isPersonalEmail: true
|
||||
}
|
||||
];
|
||||
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||
import sendEmail from '$defer/sendEmail';
|
||||
import sendEmail from '$nodemailer/sendEmail';
|
||||
|
||||
const supabase = getSupabase();
|
||||
|
||||
@@ -25,10 +25,11 @@ export async function POST({ request }) {
|
||||
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
|
||||
}
|
||||
|
||||
await sendEmail({
|
||||
to,
|
||||
subject: 'Thank you so so so much for choosing ClassroomIO!',
|
||||
content: `
|
||||
const emailData = [
|
||||
{
|
||||
to,
|
||||
subject: 'Thank you so so so much for choosing ClassroomIO!',
|
||||
content: `
|
||||
<p>Dear ${name},</p>
|
||||
<p>My name is Best the CEO of ClassroomIO and I will personally like to welcome to the vibrant community of ClassroomIO!</p>
|
||||
<p>
|
||||
@@ -47,8 +48,10 @@ export async function POST({ request }) {
|
||||
<a href="https://app.classroomio.com">Go to Dashboard</a>
|
||||
</div>
|
||||
`,
|
||||
isPersonalEmail: true
|
||||
});
|
||||
isPersonalEmail: true
|
||||
}
|
||||
];
|
||||
await sendEmail(emailData);
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
|
||||
Reference in New Issue
Block a user