Skip to content

Commit 548ba88

Browse files
committed
Improve Emailable resilience
1 parent 41a5de8 commit 548ba88

1 file changed

Lines changed: 33 additions & 25 deletions

File tree

apps/backend/src/lib/emails.tsx

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -78,34 +78,42 @@ async function _sendEmailWithoutRetries(options: SendEmailOptions): Promise<Resu
7878
if (options.emailConfig.type === 'shared' && emailableApiKey) {
7979
await traceSpan('verifying email addresses with Emailable', async () => {
8080
toArray = (await Promise.all(toArray.map(async (to) => {
81-
const emailableResponseResult = await Result.retry(async (attempt) => {
82-
const res = await fetch(`https://api.emailable.com/v1/verify?email=${encodeURIComponent(options.to as string)}&api_key=${emailableApiKey}`);
83-
if (res.status === 249) {
84-
const text = await res.text();
85-
console.log('Emailable is taking longer than expected, retrying...', text, { to: options.to });
86-
return Result.error(new Error("Emailable API returned a 249 error for " + options.to + ". This means it takes some more time to verify the email address. Response body: " + text));
81+
try {
82+
const emailableResponseResult = await Result.retry(async (attempt) => {
83+
const res = await fetch(`https://api.emailable.com/v1/verify?email=${encodeURIComponent(options.to as string)}&api_key=${emailableApiKey}`);
84+
if (res.status === 249) {
85+
const text = await res.text();
86+
console.log('Emailable is taking longer than expected, retrying...', text, { to: options.to });
87+
return Result.error(new Error("Emailable API returned a 249 error for " + options.to + ". This means it takes some more time to verify the email address. Response body: " + text));
88+
}
89+
return Result.ok(res);
90+
}, 4, { exponentialDelayBase: 4000 });
91+
if (emailableResponseResult.status === 'error') {
92+
throw new StackAssertionError("Timed out while verifying email address with Emailable", {
93+
to: options.to,
94+
emailableResponseResult,
95+
});
96+
}
97+
const emailableResponse = emailableResponseResult.data;
98+
if (!emailableResponse.ok) {
99+
throw new StackAssertionError("Failed to verify email address with Emailable", {
100+
to: options.to,
101+
emailableResponse,
102+
emailableResponseText: await emailableResponse.text(),
103+
});
104+
}
105+
const json = await emailableResponse.json();
106+
console.log('emailableResponse', json);
107+
if (json.state === 'undeliverable' || json.disposable) {
108+
console.log('email not deliverable', to, json);
109+
return null;
87110
}
88-
return Result.ok(res);
89-
}, 4, { exponentialDelayBase: 4000 });
90-
if (emailableResponseResult.status === 'error') {
91-
captureError("emailable-api-timeout", emailableResponseResult.error);
111+
return to;
112+
} catch (error) {
113+
// if something goes wrong with the Emailable API (eg. 500, ran out of credits, etc.), we just send the email anyway
114+
captureError("emailable-api-error", error);
92115
return to;
93116
}
94-
const emailableResponse = emailableResponseResult.data;
95-
if (!emailableResponse.ok) {
96-
throw new StackAssertionError("Failed to verify email address with Emailable", {
97-
to: options.to,
98-
emailableResponse,
99-
emailableResponseText: await emailableResponse.text(),
100-
});
101-
}
102-
const json = await emailableResponse.json();
103-
console.log('emailableResponse', json);
104-
if (json.state === 'undeliverable' || json.disposable) {
105-
console.log('email not deliverable', to, json);
106-
return null;
107-
}
108-
return to;
109117
}))).filter((to): to is string => to !== null);
110118
});
111119
}

0 commit comments

Comments
 (0)