auto unsubscribe on bounce and compaints (#117)
* auto unsubscribe on bounce and compaints * console
This commit is contained in:
@@ -141,6 +141,7 @@ export const contactsRouter = createTRPCRouter({
|
||||
subscribed: true,
|
||||
createdAt: true,
|
||||
contactBookId: true,
|
||||
unsubscribeReason: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
|
@@ -2,7 +2,12 @@ import { EmailRenderer } from "@unsend/email-editor/src/renderer";
|
||||
import { db } from "../db";
|
||||
import { createHash } from "crypto";
|
||||
import { env } from "~/env";
|
||||
import { Campaign, Contact, EmailStatus } from "@prisma/client";
|
||||
import {
|
||||
Campaign,
|
||||
Contact,
|
||||
EmailStatus,
|
||||
UnsubscribeReason,
|
||||
} from "@prisma/client";
|
||||
import { validateDomainFromEmail } from "./domain-service";
|
||||
import { EmailQueueService } from "./email-queue-service";
|
||||
import { Queue, Worker } from "bullmq";
|
||||
@@ -91,7 +96,7 @@ export function createUnsubUrl(contactId: string, campaignId: string) {
|
||||
return `${env.NEXTAUTH_URL}/unsubscribe?id=${unsubId}&hash=${unsubHash}`;
|
||||
}
|
||||
|
||||
export async function unsubscribeContact(id: string, hash: string) {
|
||||
export async function unsubscribeContactFromLink(id: string, hash: string) {
|
||||
const [contactId, campaignId] = id.split("-");
|
||||
|
||||
if (!contactId || !campaignId) {
|
||||
@@ -107,6 +112,18 @@ export async function unsubscribeContact(id: string, hash: string) {
|
||||
throw new Error("Invalid unsubscribe link");
|
||||
}
|
||||
|
||||
return await unsubscribeContact(
|
||||
contactId,
|
||||
campaignId,
|
||||
UnsubscribeReason.UNSUBSCRIBED
|
||||
);
|
||||
}
|
||||
|
||||
export async function unsubscribeContact(
|
||||
contactId: string,
|
||||
campaignId: string,
|
||||
reason: UnsubscribeReason
|
||||
) {
|
||||
// Update the contact's subscription status
|
||||
try {
|
||||
const contact = await db.contact.findUnique({
|
||||
@@ -120,7 +137,7 @@ export async function unsubscribeContact(id: string, hash: string) {
|
||||
if (contact.subscribed) {
|
||||
await db.contact.update({
|
||||
where: { id: contactId },
|
||||
data: { subscribed: false },
|
||||
data: { subscribed: false, unsubscribeReason: reason },
|
||||
});
|
||||
|
||||
await db.campaign.update({
|
||||
|
@@ -50,6 +50,8 @@ export async function createDomain(
|
||||
) {
|
||||
const domainStr = tldts.getDomain(name);
|
||||
|
||||
console.log("Creating domain", { domainStr, name, region });
|
||||
|
||||
if (!domainStr) {
|
||||
throw new Error("Invalid domain");
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
import { EmailStatus, Prisma } from "@prisma/client";
|
||||
import { EmailStatus, Prisma, UnsubscribeReason } from "@prisma/client";
|
||||
import { SesClick, SesEvent, SesEventDataKey } from "~/types/aws-types";
|
||||
import { db } from "../db";
|
||||
import { updateCampaignAnalytics } from "./campaign-service";
|
||||
import {
|
||||
unsubscribeContact,
|
||||
updateCampaignAnalytics,
|
||||
} from "./campaign-service";
|
||||
import { env } from "~/env";
|
||||
import { getRedis } from "../redis";
|
||||
import { Queue, Worker } from "bullmq";
|
||||
@@ -100,6 +103,8 @@ export async function parseSesHook(data: SesEvent) {
|
||||
mailStatus !== "CLICKED" ||
|
||||
!(mailData as SesClick).link.startsWith(`${env.NEXTAUTH_URL}/unsubscribe`)
|
||||
) {
|
||||
await checkUnsubscribe(email.campaignId, email.contactId!, mailStatus);
|
||||
|
||||
const mailEvent = await db.emailEvent.findFirst({
|
||||
where: {
|
||||
emailId: email.id,
|
||||
@@ -124,6 +129,22 @@ export async function parseSesHook(data: SesEvent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkUnsubscribe(
|
||||
campaignId: string,
|
||||
contactId: string,
|
||||
event: EmailStatus
|
||||
) {
|
||||
if (event === EmailStatus.BOUNCED || event === EmailStatus.COMPLAINED) {
|
||||
return unsubscribeContact(
|
||||
contactId,
|
||||
campaignId,
|
||||
event === EmailStatus.BOUNCED
|
||||
? UnsubscribeReason.BOUNCED
|
||||
: UnsubscribeReason.COMPLAINED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getEmailStatus(data: SesEvent) {
|
||||
const { eventType } = data;
|
||||
|
||||
|
Reference in New Issue
Block a user