Skip to content

Commit

Permalink
Fix email rate limit bug. (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
antiantivirus authored May 27, 2024
1 parent 110b7b2 commit 744bee3
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 168 deletions.
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

0 comments on commit 744bee3

Please sign in to comment.