Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix email rate limit bug. #129

Merged
merged 2 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 44 additions & 19 deletions lib/resend/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dayjs from "dayjs";

export async function sendEmail(artist, show, severity) {
try {
const data = await resend.sendEmail({
const { data, error } = await resend.emails.send({
from: "Refuge Worldwide <[email protected]>",
to: artist.email,
subject: subject(severity),
Expand All @@ -25,11 +25,16 @@ export async function sendEmail(artist, show, severity) {
showId: show.sys.id,
}),
});
if (error) {
throw new Error(error.name);
}

return data;
} catch (error) {
// send message to slack saying there was an issue sending the email
console.log(error);
sendSlackMessage(
`Failed to send email request to ${artist.name}(${artist.email}) on show *${show.title}*. ${error}. <@U04HG3VHHEW>`
`Failed to send email request to ${artist.name}(${artist.email}) on show *${show.title}*. ${error.name} - ${error.message}. <@U04HG3VHHEW>`
);
throw new Error(error);
}
Expand All @@ -40,7 +45,7 @@ export async function sendConfirmationEmail(show) {
show.artists.map(async (artist) => {
if (artist.email) {
try {
const data = await resend.sendEmail({
const { data, error } = await resend.emails.send({
from: "Refuge Worldwide <[email protected]>",
to: artist.email,
subject:
Expand All @@ -59,11 +64,17 @@ export async function sendConfirmationEmail(show) {
showId: show.id,
}),
});

if (error) {
throw new Error(error.name);
}

return data;
} catch (error) {
// send message to slack saying there was an issue sending the email
console.log(error);
sendSlackMessage(
`Failed to send email request to ${artist.name}(${artist.email}) on show *${show.title}*. ${error}. <@U04HG3VHHEW>`
`Failed to send email request to ${artist.name}(${artist.email}) on show *${show.title}*. ${error.name} - ${error.message}. <@U04HG3VHHEW>`
);
}
}
Expand All @@ -72,21 +83,35 @@ export async function sendConfirmationEmail(show) {
}

export async function sendArtworkEmail(artist, date) {
const data = await resend.sendEmail({
from: "Refuge Worldwide <[email protected]>",
to: artist.email,
subject:
"Your show artwork for " + dayjs(date).format("dddd") + " is now ready",
reply_to: [
"[email protected]",
"[email protected]",
"[email protected]",
],
react: ShowArtworkEmail({
userName: artist.name,
showDate: date,
}),
});
try {
const { data, error } = await resend.emails.send({
from: "Refuge Worldwide <[email protected]>",
to: artist.email,
subject:
"Your show artwork for " + dayjs(date).format("dddd") + " is now ready",
reply_to: [
"[email protected]",
"[email protected]",
"[email protected]",
],
react: ShowArtworkEmail({
userName: artist.name,
showDate: date,
}),
});

if (error) {
throw new Error(error.name);
}

return data;
} catch (error) {
// send message to slack saying there was an issue sending the email
console.log(error);
sendSlackMessage(
`Failed to send artwork email to ${artist.name}(${artist.email}). ${error.name} - ${error.message}. <@U04HG3VHHEW>`
);
}
}

function subject(severity: string) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"react-player": "^2.13.0",
"react-select": "^5.6.1",
"react-select-async-paginate": "^0.7.3",
"resend": "^1.0.0",
"resend": "^3.2.0",
"sharp": "^0.31.3",
"smoothscroll-polyfill": "^0.4.4",
"swr": "^2.1.1",
Expand Down
87 changes: 51 additions & 36 deletions pages/api/admin/artwork-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,66 @@ import { sendArtworkEmail } from "../../../lib/resend/email";
import { getUpcomingShowsByDate } from "../../../lib/contentful/pages/radio";
import dayjs from "dayjs";
import { sendSlackMessage } from "../../../lib/slack";

const contentfulSpaceId = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const rateLimitDelay = 105; // 105 milliseconds delay to respect rate limits

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}

const values = req.body;
switch (req.method) {
case "POST":
try {
const date = dayjs(values.date, "YYYY-MM-DD");
console.log(date);
const shows = await getUpcomingShowsByDate(date, true, "Submitted");
console.log(shows);
await Promise.all(
shows.map(async (show) => {
let showEmailed = false;
await Promise.all(
show.artistsCollection.items.map(async (artist) => {
if (artist.email) {
try {
await sendArtworkEmail(artist, date);
showEmailed = true;
} catch (error) {
// send message to slack saying there was an issue sending the email
console.log(error);
sendSlackMessage(
`Failed to send email request to ${artist.name}(${artist.email}) on show *${show.title}*. ${error}. <@U04HG3VHHEW>`
);
}
}
})

try {
const date = dayjs(values.date, "YYYY-MM-DD");
console.log(`Processing emails for date: ${date.format("YYYY-MM-DD")}`);

const shows = await getUpcomingShowsByDate(date, true, "Submitted");
console.log(`Found ${shows.length} shows to process`);

const emailedArtists = new Set(); // Set to track emailed artist emails

for (const show of shows) {
let showEmailed = false;

for (const artist of show.artistsCollection.items) {
if (artist.email && !emailedArtists.has(artist.email)) {
try {
await sendArtworkEmail(artist, date);
emailedArtists.add(artist.email); // Add artist email to the set after emailing
showEmailed = true;
await new Promise((resolve) => setTimeout(resolve, rateLimitDelay)); // Respect the rate limit
} catch (error) {
console.error(
`Failed to send email to ${artist.name} (${artist.email}) for show "${show.title}":`,
error
);
if (!showEmailed) {
sendSlackMessage(
`Show *${show.title}* has no emails assigned. They did not recieve artwork email. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${show.sys.id}|Edit show >`
);
}
})
);
await sendSlackMessage(
`Failed to send email request to ${artist.name} (${artist.email}) for show *${show.title}*. Error: ${error.message}. <@U04HG3VHHEW>`
);
}
} else if (!artist.email) {
console.warn(`${artist.name} does not have an email`);
await sendSlackMessage(
`*${artist.name}* has no email assigned. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${artist.sys.id}|Add email >`
);
}
}

return res.status(200).json("Artwork email sent");
} catch (error) {
console.log(error);
return res.status(400).json({ message: error.message });
if (!showEmailed) {
await sendSlackMessage(
`Show *${show.title}* has no emails assigned. No artwork email was sent. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${show.sys.id}|Edit show >`
);
}
}

return res.status(200).json("Artwork emails sent successfully");
} catch (error) {
console.error("Error processing emails:", error);
return res.status(400).json({ message: error.message });
}
}
46 changes: 24 additions & 22 deletions pages/api/cron/show-submission-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,32 @@ async function sendEmails(
shows: ShowInterface[],
severity: "initial" | "follow-up" | "late"
) {
await Promise.all(
shows.map(async (show) => {
let showEmailed = false;
await Promise.all(
show.artistsCollection.items.map(async (artist) => {
if (artist.email) {
await sendEmail(artist, show, severity);
showEmailed = true;
} else {
// send message to slack saying artist does not have email address assigned to them.
console.log(artist.name + " does not have email");
sendSlackMessage(
`*${artist.name}* has no email assigned to them. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${artist.sys.id}|Add email >`
);
}
})
);
if (!showEmailed) {
sendSlackMessage(
`Show *${show.title}* has no emails assigned. They did not recieve ${severity} email. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${show.sys.id}|Edit show >`
const delay = 105; // 105 milliseconds delay

for (const show of shows) {
let showEmailed = false;

const emailPromises = show.artistsCollection.items.map(async (artist) => {
if (artist.email) {
await sendEmail(artist, show, severity);
showEmailed = true;
await new Promise((resolve) => setTimeout(resolve, delay)); // Respect the rate limit
} else {
console.log(`${artist.name} does not have an email`);
await sendSlackMessage(
`*${artist.name}* has no email assigned to them. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${artist.sys.id}|Add email >`
);
}
})
);
});

await Promise.all(emailPromises);

if (!showEmailed) {
await sendSlackMessage(
`Show *${show.title}* has no emails assigned. They did not receive ${severity} email. <https://app.contentful.com/spaces/${contentfulSpaceId}/entries/${show.sys.id}|Edit show >`
);
}
}
}

function checkEmails(shows: ShowInterface[]) {
Expand Down
Loading
Loading