feat: Add dedicated received type

This commit is contained in:
Dries Augustyns
2026-02-18 16:24:55 +01:00
parent 3330d83d08
commit f947ee6f22
8 changed files with 45 additions and 3 deletions
+1 -1
View File
@@ -154,7 +154,7 @@ export class Webhooks {
body: '', // Inbound emails don't have body content in our system
from: recipientEmail, // The recipient address that received the email
sourceType: EmailSourceType.INBOUND,
status: EmailStatus.DELIVERED, // Inbound emails are already delivered
status: EmailStatus.RECEIVED, // Inbound emails use RECEIVED status
deliveredAt: new Date(body.mail?.timestamp || new Date()),
},
});
+19
View File
@@ -376,6 +376,9 @@ export class ActivityService {
if (!types || types.includes(ActivityType.EMAIL_DELIVERED)) {
orConditions.push({deliveredAt: {not: null, ...dateFilter}});
}
if (!types || types.includes(ActivityType.EMAIL_RECEIVED)) {
orConditions.push({deliveredAt: {not: null, ...dateFilter}, sourceType: 'INBOUND'});
}
if (!types || types.includes(ActivityType.EMAIL_OPENED)) {
orConditions.push({openedAt: {not: null, ...dateFilter}});
}
@@ -485,6 +488,22 @@ export class ActivityService {
});
}
if (
email.deliveredAt &&
email.sourceType === 'INBOUND' &&
(!types || types.includes(ActivityType.EMAIL_RECEIVED)) &&
isInDateRange(email.deliveredAt)
) {
activities.push({
id: `${email.id}_received`,
type: ActivityType.EMAIL_RECEIVED,
timestamp: email.deliveredAt,
contactEmail: email.contact.email,
contactId: email.contactId,
metadata: baseMetadata,
});
}
if (email.openedAt && (!types || types.includes(ActivityType.EMAIL_OPENED)) && isInDateRange(email.openedAt)) {
activities.push({
id: `${email.id}_opened`,
+3 -1
View File
@@ -585,10 +585,11 @@ export class EmailService {
: {}),
};
const [total, sent, delivered, opened, clicked, bounced, failed] = await Promise.all([
const [total, sent, delivered, received, opened, clicked, bounced, failed] = await Promise.all([
prisma.email.count({where}),
prisma.email.count({where: {...where, status: EmailStatus.SENT}}),
prisma.email.count({where: {...where, status: EmailStatus.DELIVERED}}),
prisma.email.count({where: {...where, status: EmailStatus.RECEIVED}}),
prisma.email.count({where: {...where, status: EmailStatus.OPENED}}),
prisma.email.count({where: {...where, status: EmailStatus.CLICKED}}),
prisma.email.count({where: {...where, status: EmailStatus.BOUNCED}}),
@@ -599,6 +600,7 @@ export class EmailService {
total,
sent,
delivered,
received,
opened,
clicked,
bounced,
+15
View File
@@ -9,6 +9,7 @@ import {
CheckCircle,
ChevronRight,
Eye,
Inbox,
MousePointerClick,
Send,
ShieldAlert,
@@ -99,6 +100,7 @@ function isEmailActivity(type: string): boolean {
return [
'email.sent',
'email.delivered',
'email.received',
'email.opened',
'email.clicked',
'email.bounced',
@@ -181,6 +183,19 @@ function getActivityConfig(activity: Activity): ActivityConfig {
},
};
case 'email.received':
return {
icon: Inbox,
color: 'text-blue-600',
bgColor: 'bg-blue-100',
title: (typeof metadata.subject === 'string' ? metadata.subject : undefined) || 'Email received',
description: typeof metadata.from === 'string' ? `From: ${metadata.from}` : 'Inbound email',
badge: {
label: 'Received',
variant: 'default',
},
};
case 'email.opened':
return {
icon: Eye,
+3 -1
View File
@@ -119,10 +119,12 @@ export default function ActivityPage() {
<SelectContent>
<SelectItem value="ALL">All Activity Types</SelectItem>
<SelectItem value="event.triggered">Events</SelectItem>
<SelectItem value="email.sent,email.delivered,email.opened,email.clicked,email.bounced,email.complaint">
<SelectItem value="email.sent,email.delivered,email.received,email.opened,email.clicked,email.bounced,email.complaint">
Emails
</SelectItem>
<SelectItem value="email.sent">Emails Sent</SelectItem>
<SelectItem value="email.delivered">Emails Delivered</SelectItem>
<SelectItem value="email.received">Emails Received</SelectItem>
<SelectItem value="email.opened">Emails Opened</SelectItem>
<SelectItem value="email.clicked">Emails Clicked</SelectItem>
<SelectItem value="email.bounced">Emails Bounced</SelectItem>
@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "EmailStatus" ADD VALUE 'RECEIVED';
+1
View File
@@ -759,6 +759,7 @@ enum EmailStatus {
SENDING // Currently being sent
SENT // Successfully sent to provider
DELIVERED // Confirmed delivered
RECEIVED // Received by platform (inbound)
OPENED // Recipient opened email
CLICKED // Recipient clicked link
BOUNCED // Bounced (hard or soft)
+1
View File
@@ -9,6 +9,7 @@ export enum ActivityType {
EVENT_TRIGGERED = 'event.triggered',
EMAIL_SENT = 'email.sent',
EMAIL_DELIVERED = 'email.delivered',
EMAIL_RECEIVED = 'email.received',
EMAIL_OPENED = 'email.opened',
EMAIL_CLICKED = 'email.clicked',
EMAIL_BOUNCED = 'email.bounced',