Skip to content

Commit 5a1e1b8

Browse files
committed
AWAITING_WEBHOOK message status
1 parent 7120ea7 commit 5a1e1b8

File tree

14 files changed

+67
-50
lines changed

14 files changed

+67
-50
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Process email status updates from external email service providers
66
- **Complained Message Status** - Track when recipients mark emails as spam
77
- **Monaco Code Editor** - Enhanced code editing experience for webhook configuration
8+
- **Awaiting Webhook Status** - Track when messages are awaiting webhook processing
89

910
### 🐛 Bug Fixes
1011

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterEnum
2+
ALTER TYPE "MessageStatus" ADD VALUE 'AWAITING_WEBHOOK';

apps/backend/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ enum MessageStatus {
195195
QUEUED
196196
PENDING
197197
SENT
198+
AWAITING_WEBHOOK
198199
OPENED
199200
CLICKED
200201
FAILED

apps/backend/src/app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ app.get("/img/:id/img.png", async (req, res) => {
134134
return
135135
}
136136

137-
if (message.status !== "SENT") return
137+
if (message.status !== "SENT" && message.status !== "AWAITING_WEBHOOK") {
138+
return
139+
}
138140

139141
await tx.message.update({
140142
where: { id },

apps/backend/src/campaign/query.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { TRPCError } from "@trpc/server"
55
import { paginationSchema } from "../utils/schemas"
66
import { Prisma } from "../../prisma/client"
77
import { resolveProps } from "../utils/pProps"
8+
import { messageStatus } from "../utils/message-status"
89

910
export const listCampaigns = authProcedure
1011
.input(z.object({ organizationId: z.string() }).merge(paginationSchema))
@@ -189,7 +190,7 @@ export const getCampaign = authProcedure
189190
where: {
190191
campaignId: campaign.id,
191192
status: {
192-
in: ["SENT", "OPENED", "CLICKED"],
193+
in: messageStatus.deliveredMessages,
193194
},
194195
},
195196
}),
@@ -203,7 +204,7 @@ export const getCampaign = authProcedure
203204
where: {
204205
campaignId: campaign.id,
205206
status: {
206-
not: "QUEUED",
207+
in: messageStatus.processedMessages,
207208
},
208209
},
209210
}),
@@ -217,7 +218,7 @@ export const getCampaign = authProcedure
217218
where: {
218219
campaignId: campaign.id,
219220
status: {
220-
in: ["OPENED", "CLICKED"],
221+
in: messageStatus.openedMessages,
221222
},
222223
},
223224
}),

apps/backend/src/cron/sendMessages.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import pMap from "p-map"
22
import { Mailer } from "../lib/Mailer"
33
import { logger } from "../utils/logger"
44
import { prisma } from "../utils/prisma"
5+
import { messageStatus } from "../utils/message-status"
56

67
import { cronJob } from "./cron.utils"
78
import { subSeconds } from "date-fns"
@@ -10,17 +11,24 @@ export const sendMessagesCron = cronJob("sendMessages", async () => {
1011
const organizations = await prisma.organization.findMany()
1112

1213
for (const organization of organizations) {
13-
const [smtpSettings, emailSettings, generalSettings] = await Promise.all([
14-
prisma.smtpSettings.findFirst({
15-
where: { organizationId: organization.id },
16-
}),
17-
prisma.emailDeliverySettings.findFirst({
18-
where: { organizationId: organization.id },
19-
}),
20-
prisma.generalSettings.findFirst({
21-
where: { organizationId: organization.id },
22-
}),
23-
])
14+
const [smtpSettings, emailSettings, generalSettings, activeWebhooks] =
15+
await Promise.all([
16+
prisma.smtpSettings.findFirst({
17+
where: { organizationId: organization.id },
18+
}),
19+
prisma.emailDeliverySettings.findFirst({
20+
where: { organizationId: organization.id },
21+
}),
22+
prisma.generalSettings.findFirst({
23+
where: { organizationId: organization.id },
24+
}),
25+
prisma.webhook.count({
26+
where: {
27+
organizationId: organization.id,
28+
isActive: true,
29+
},
30+
}),
31+
])
2432

2533
if (!smtpSettings || !emailSettings) {
2634
logger.warn(
@@ -33,7 +41,7 @@ export const sendMessagesCron = cronJob("sendMessages", async () => {
3341
const sentInWindow = await prisma.message.count({
3442
where: {
3543
status: {
36-
in: ["PENDING", "SENT", "OPENED", "CLICKED", "COMPLAINED"],
44+
in: messageStatus.processedMessages,
3745
},
3846
sentAt: {
3947
gte: windowStart,
@@ -100,14 +108,7 @@ export const sendMessagesCron = cronJob("sendMessages", async () => {
100108
Messages: {
101109
every: {
102110
status: {
103-
in: [
104-
"SENT",
105-
"FAILED",
106-
"OPENED",
107-
"CLICKED",
108-
"CANCELLED",
109-
"COMPLAINED",
110-
],
111+
in: messageStatus.completedMessages,
111112
},
112113
},
113114
},
@@ -158,12 +159,15 @@ export const sendMessagesCron = cronJob("sendMessages", async () => {
158159
from: `${fromName} <${fromEmail}>`,
159160
})
160161

162+
// If webhooks are active, set status to AWAITING_WEBHOOK, otherwise SENT
163+
const successStatus = activeWebhooks > 0 ? "AWAITING_WEBHOOK" : "SENT"
164+
161165
await prisma.message.update({
162166
where: { id: message.id },
163167
data: {
164168
messageId: result.messageId,
165169
status: result.success
166-
? "SENT"
170+
? successStatus
167171
: message.tries >= emailSettings.maxRetries
168172
? "FAILED"
169173
: "RETRYING",

apps/backend/src/dashboard/query.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { MessageStatus } from "../../prisma/client"
66
import { countDbSize, subscriberGrowthQuery } from "../../prisma/client/sql"
77
import pMap from "p-map"
88
import { subMonths } from "date-fns"
9+
import { messageStatus } from "../utils/message-status"
910

1011
export const getDashboardStats = authProcedure
1112
.input(
@@ -98,7 +99,7 @@ export const getDashboardStats = authProcedure
9899
where: {
99100
campaignId: campaign.id,
100101
status: {
101-
in: ["SENT", "OPENED", "CLICKED"],
102+
in: messageStatus.deliveredMessages,
102103
},
103104
},
104105
}),

apps/backend/src/message/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { prisma } from "../utils/prisma"
22
import { MessageStatus } from "../../prisma/client"
3+
import { messageStatus } from "../utils/message-status"
34

45
interface MessageQueryOptions {
56
campaignId?: string
@@ -35,7 +36,7 @@ export async function getDeliveredMessages({
3536
return findMessagesByStatus({
3637
campaignId,
3738
organizationId,
38-
status: ["SENT", "CLICKED", "OPENED"],
39+
status: messageStatus.deliveredMessages,
3940
})
4041
}
4142

@@ -57,7 +58,7 @@ export async function getOpenedMessages({
5758
return findMessagesByStatus({
5859
campaignId,
5960
organizationId,
60-
status: ["OPENED", "CLICKED"], // Clicked implies opened
61+
status: messageStatus.openedMessages,
6162
})
6263
}
6364

apps/backend/src/stats/query.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
countDistinctRecipients,
99
countDistinctRecipientsInTimeRange,
1010
} from "../../prisma/client/sql"
11-
import { MessageStatus } from "../../prisma/client"
11+
import { messageStatus } from "../utils/message-status"
1212

1313
export const getStats = authProcedure
1414
.input(
@@ -21,14 +21,6 @@ export const getStats = authProcedure
2121
const thirtyDaysAgo = subDays(now, 30)
2222
const sixtyDaysAgo = subDays(now, 60)
2323

24-
const processedMessageStatuses: MessageStatus[] = [
25-
"SENT",
26-
"CLICKED",
27-
"OPENED",
28-
"FAILED",
29-
"COMPLAINED",
30-
]
31-
3224
// Check auth
3325
const hasAccess = await prisma.userOrganization.findFirst({
3426
where: {
@@ -52,7 +44,7 @@ export const getStats = authProcedure
5244
Campaign: {
5345
organizationId: input.organizationId,
5446
},
55-
status: { in: processedMessageStatuses },
47+
status: { in: messageStatus.processedMessages },
5648
},
5749
}),
5850
prisma.message.count({
@@ -64,7 +56,7 @@ export const getStats = authProcedure
6456
gte: thirtyDaysAgo,
6557
lt: now,
6658
},
67-
status: { in: processedMessageStatuses },
59+
status: { in: messageStatus.processedMessages },
6860
},
6961
}),
7062
prisma.message.count({
@@ -76,7 +68,7 @@ export const getStats = authProcedure
7668
gte: sixtyDaysAgo,
7769
lt: thirtyDaysAgo,
7870
},
79-
status: { in: processedMessageStatuses },
71+
status: { in: messageStatus.processedMessages },
8072
},
8173
}),
8274
])
@@ -100,7 +92,7 @@ export const getStats = authProcedure
10092
const openedMessages = await prisma.message.count({
10193
where: {
10294
status: {
103-
in: ["CLICKED", "OPENED"],
95+
in: messageStatus.openedMessages,
10496
},
10597
Campaign: {
10698
organizationId: input.organizationId,
@@ -118,7 +110,7 @@ export const getStats = authProcedure
118110
const openedMessages = await prisma.message.count({
119111
where: {
120112
status: {
121-
in: ["CLICKED", "OPENED"],
113+
in: messageStatus.openedMessages,
122114
},
123115
Campaign: {
124116
organizationId: input.organizationId,
@@ -209,7 +201,7 @@ export const getStats = authProcedure
209201
const deliveredMessages = await prisma.message.count({
210202
where: {
211203
status: {
212-
in: ["SENT", "CLICKED", "OPENED"],
204+
in: messageStatus.deliveredMessages,
213205
},
214206
Campaign: {
215207
organizationId: input.organizationId,
@@ -230,7 +222,7 @@ export const getStats = authProcedure
230222
const deliveredMessages = await prisma.message.count({
231223
where: {
232224
status: {
233-
in: ["SENT", "CLICKED", "OPENED"],
225+
in: messageStatus.deliveredMessages,
234226
},
235227
Campaign: {
236228
organizationId: input.organizationId,

apps/backend/src/utils/message-status.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,19 @@ import { MessageStatus } from "../../prisma/client"
22

33
export const messageStatus = {
44
pendingMessages: ["QUEUED", "PENDING", "RETRYING"] as MessageStatus[],
5+
deliveredMessages: ["SENT", "OPENED", "CLICKED"] as MessageStatus[],
6+
openedMessages: ["OPENED", "CLICKED"] as MessageStatus[],
7+
processedMessages: [
8+
"SENT",
9+
"AWAITING_WEBHOOK",
10+
"OPENED",
11+
"CLICKED",
12+
"FAILED",
13+
"COMPLAINED",
14+
] as MessageStatus[],
515
completedMessages: [
616
"SENT",
17+
"AWAITING_WEBHOOK",
718
"OPENED",
819
"CLICKED",
920
"FAILED",

0 commit comments

Comments
 (0)