fix: add catch for rate limit errors

This commit is contained in:
Chris Anderson 2025-07-15 10:06:02 -05:00
parent 5483f0ef30
commit 3df6c003aa
4 changed files with 23 additions and 4 deletions

View file

@ -0,0 +1,3 @@
import { ContextError } from '../../error/ErrorHandler'
export class RateLimitEmailError extends ContextError { }

View file

@ -1,4 +1,4 @@
import Job from '../../queue/Job'
import Job, { RetryError } from '../../queue/Job'
import { MessageTrigger } from '../MessageTrigger'
import { updateSendState } from '../../campaigns/CampaignService'
import { loadEmailChannel } from './index'
@ -7,6 +7,7 @@ import { EmailTemplate } from '../../render/Template'
import { EncodedJob } from '../../queue'
import App from '../../app'
import { releaseLock } from '../../core/Lock'
import { RateLimitEmailError } from './EmailError'
export default class EmailJob extends Job {
static $name = 'email'
@ -42,6 +43,11 @@ export default class EmailJob extends Job {
const result = await channel.send(template, data)
await finalizeSend(data, result)
} catch (error: any) {
// If its a rate limit error, lets re-add to the queue to retry later
if (error instanceof RateLimitEmailError) {
throw new RetryError()
}
await failSend(data, error)
} finally {
await releaseLock(messageLock(campaign, user))

View file

@ -2,6 +2,7 @@ import nodemailer from 'nodemailer'
import { LoggerProviderName } from '../LoggerProvider'
import Provider, { ProviderGroup } from '../Provider'
import { Email } from './Email'
import { RateLimitEmailError } from './EmailError'
export type EmailProviderName = 'ses' | 'smtp' | 'mailgun' | 'sendgrid' | LoggerProviderName
@ -14,7 +15,16 @@ export default abstract class EmailProvider extends Provider {
static group = 'email' as ProviderGroup
async send(message: Email): Promise<any> {
return await this.transport?.sendMail(message)
try {
return await this.transport?.sendMail(message)
} catch (error: any) {
const isThrottle = error.code === 'Throttling'
|| error.name === 'ThrottlingException'
|| (error.message && error.message.includes('Throttling'))
|| (error.cause && error.cause.name === 'ThrottlingException')
if (isThrottle) throw new RateLimitEmailError(error.message)
throw error
}
}
async verify(): Promise<boolean> {

View file

@ -144,8 +144,8 @@ const subscriptionPreferencesTemplate = compileTemplate<SubscriptionPreferencesA
<main>
{{#if subscriptions}}
<form action="{{url}}" method="post">
<h1>Subscription Preferences</h1>
<p>Choose which notifications you would like to continue to receive.</p>
<h1>Communication Preferences</h1>
<p>Choose which methods of communication you would like to continue to receive:</p>
{{#if showUpdatedMessage}}
<div class="alert-success">
Your preferences have been updated!