convert text to html for marketing emails (#55)
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
"bullmq": "^5.8.2",
|
"bullmq": "^5.8.2",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"hono": "^4.2.2",
|
"hono": "^4.2.2",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
"lucide-react": "^0.359.0",
|
"lucide-react": "^0.359.0",
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
"@next/eslint-plugin-next": "^14.2.2",
|
"@next/eslint-plugin-next": "^14.2.2",
|
||||||
"@prisma/extension-optimize": "^0.10.0",
|
"@prisma/extension-optimize": "^0.10.0",
|
||||||
"@types/eslint": "^8.56.2",
|
"@types/eslint": "^8.56.2",
|
||||||
|
"@types/html-to-text": "^9.0.4",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^20.11.20",
|
"@types/node": "^20.11.20",
|
||||||
"@types/react": "^18.2.57",
|
"@types/react": "^18.2.57",
|
||||||
|
@@ -141,14 +141,18 @@ export async function sendEmailThroughSes({
|
|||||||
},
|
},
|
||||||
Body: {
|
Body: {
|
||||||
// Body
|
// Body
|
||||||
Text: {
|
Text: text
|
||||||
|
? {
|
||||||
Data: text, // required
|
Data: text, // required
|
||||||
Charset: "UTF-8",
|
Charset: "UTF-8",
|
||||||
},
|
}
|
||||||
Html: {
|
: undefined,
|
||||||
|
Html: html
|
||||||
|
? {
|
||||||
Data: html, // required
|
Data: html, // required
|
||||||
Charset: "UTF-8",
|
Charset: "UTF-8",
|
||||||
},
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
...(unsubUrl
|
...(unsubUrl
|
||||||
? {
|
? {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Job, Queue, Worker } from "bullmq";
|
import { Job, Queue, Worker } from "bullmq";
|
||||||
import { env } from "~/env";
|
import { env } from "~/env";
|
||||||
import { EmailAttachment } from "~/types";
|
import { EmailAttachment } from "~/types";
|
||||||
|
import { convert as htmlToText } from "html-to-text";
|
||||||
import { getConfigurationSetName } from "~/utils/ses-utils";
|
import { getConfigurationSetName } from "~/utils/ses-utils";
|
||||||
import { db } from "../db";
|
import { db } from "../db";
|
||||||
import { sendEmailThroughSes, sendEmailWithAttachments } from "../aws/ses";
|
import { sendEmailThroughSes, sendEmailWithAttachments } from "../aws/ses";
|
||||||
@@ -164,13 +165,19 @@ async function executeEmail(
|
|||||||
console.log(`[EmailQueueService]: Sending email ${email.id}`);
|
console.log(`[EmailQueueService]: Sending email ${email.id}`);
|
||||||
const unsubUrl = job.data.unsubUrl;
|
const unsubUrl = job.data.unsubUrl;
|
||||||
|
|
||||||
|
const text = email.text
|
||||||
|
? email.text
|
||||||
|
: email.campaignId && email.html
|
||||||
|
? htmlToText(email.html)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const messageId = attachments.length
|
const messageId = attachments.length
|
||||||
? await sendEmailWithAttachments({
|
? await sendEmailWithAttachments({
|
||||||
to: email.to,
|
to: email.to,
|
||||||
from: email.from,
|
from: email.from,
|
||||||
subject: email.subject,
|
subject: email.subject,
|
||||||
text: email.text ?? "",
|
text,
|
||||||
html: email.html ?? undefined,
|
html: email.html ?? undefined,
|
||||||
region: domain?.region ?? env.AWS_DEFAULT_REGION,
|
region: domain?.region ?? env.AWS_DEFAULT_REGION,
|
||||||
configurationSetName,
|
configurationSetName,
|
||||||
@@ -181,7 +188,7 @@ async function executeEmail(
|
|||||||
from: email.from,
|
from: email.from,
|
||||||
subject: email.subject,
|
subject: email.subject,
|
||||||
replyTo: email.replyTo ?? undefined,
|
replyTo: email.replyTo ?? undefined,
|
||||||
text: email.text ?? "",
|
text,
|
||||||
html: email.html ?? undefined,
|
html: email.html ?? undefined,
|
||||||
region: domain?.region ?? env.AWS_DEFAULT_REGION,
|
region: domain?.region ?? env.AWS_DEFAULT_REGION,
|
||||||
configurationSetName,
|
configurationSetName,
|
||||||
@@ -192,7 +199,7 @@ async function executeEmail(
|
|||||||
// Delete attachments after sending the email
|
// Delete attachments after sending the email
|
||||||
await db.email.update({
|
await db.email.update({
|
||||||
where: { id: email.id },
|
where: { id: email.id },
|
||||||
data: { sesEmailId: messageId, attachments: undefined },
|
data: { sesEmailId: messageId, text, attachments: undefined },
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
await db.emailEvent.create({
|
await db.emailEvent.create({
|
||||||
|
83
pnpm-lock.yaml
generated
83
pnpm-lock.yaml
generated
@@ -188,6 +188,9 @@ importers:
|
|||||||
hono:
|
hono:
|
||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2
|
version: 4.2.2
|
||||||
|
html-to-text:
|
||||||
|
specifier: ^9.0.5
|
||||||
|
version: 9.0.5
|
||||||
install:
|
install:
|
||||||
specifier: ^0.13.0
|
specifier: ^0.13.0
|
||||||
version: 0.13.0
|
version: 0.13.0
|
||||||
@@ -264,6 +267,9 @@ importers:
|
|||||||
'@types/eslint':
|
'@types/eslint':
|
||||||
specifier: ^8.56.2
|
specifier: ^8.56.2
|
||||||
version: 8.56.5
|
version: 8.56.5
|
||||||
|
'@types/html-to-text':
|
||||||
|
specifier: ^9.0.4
|
||||||
|
version: 9.0.4
|
||||||
'@types/mime-types':
|
'@types/mime-types':
|
||||||
specifier: ^2.1.4
|
specifier: ^2.1.4
|
||||||
version: 2.1.4
|
version: 2.1.4
|
||||||
@@ -6481,6 +6487,10 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 3.0.2
|
'@types/unist': 3.0.2
|
||||||
|
|
||||||
|
/@types/html-to-text@9.0.4:
|
||||||
|
resolution: {integrity: sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/http-cache-semantics@4.0.4:
|
/@types/http-cache-semantics@4.0.4:
|
||||||
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -8913,7 +8923,7 @@ packages:
|
|||||||
eslint: 8.57.0
|
eslint: 8.57.0
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
eslint-plugin-import: 2.29.1(eslint@8.57.0)
|
||||||
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
||||||
eslint-plugin-react: 7.34.0(eslint@8.57.0)
|
eslint-plugin-react: 7.34.0(eslint@8.57.0)
|
||||||
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
|
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
|
||||||
@@ -8971,7 +8981,7 @@ packages:
|
|||||||
enhanced-resolve: 5.16.0
|
enhanced-resolve: 5.16.0
|
||||||
eslint: 8.57.0
|
eslint: 8.57.0
|
||||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.7.3
|
get-tsconfig: 4.7.3
|
||||||
is-core-module: 2.13.1
|
is-core-module: 2.13.1
|
||||||
@@ -9105,41 +9115,6 @@ packages:
|
|||||||
ignore: 5.3.1
|
ignore: 5.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
|
||||||
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
|
||||||
engines: {node: '>=4'}
|
|
||||||
peerDependencies:
|
|
||||||
'@typescript-eslint/parser': '*'
|
|
||||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@typescript-eslint/parser':
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2)
|
|
||||||
array-includes: 3.1.7
|
|
||||||
array.prototype.findlastindex: 1.2.4
|
|
||||||
array.prototype.flat: 1.3.2
|
|
||||||
array.prototype.flatmap: 1.3.2
|
|
||||||
debug: 3.2.7
|
|
||||||
doctrine: 2.1.0
|
|
||||||
eslint: 8.57.0
|
|
||||||
eslint-import-resolver-node: 0.3.9
|
|
||||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
|
||||||
hasown: 2.0.2
|
|
||||||
is-core-module: 2.13.1
|
|
||||||
is-glob: 4.0.3
|
|
||||||
minimatch: 3.1.2
|
|
||||||
object.fromentries: 2.0.7
|
|
||||||
object.groupby: 1.0.2
|
|
||||||
object.values: 1.1.7
|
|
||||||
semver: 6.3.1
|
|
||||||
tsconfig-paths: 3.15.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- eslint-import-resolver-typescript
|
|
||||||
- eslint-import-resolver-webpack
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0)(eslint@8.57.0):
|
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0)(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -9175,6 +9150,40 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-plugin-import@2.29.1(eslint@8.57.0):
|
||||||
|
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
peerDependencies:
|
||||||
|
'@typescript-eslint/parser': '*'
|
||||||
|
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@typescript-eslint/parser':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
array-includes: 3.1.7
|
||||||
|
array.prototype.findlastindex: 1.2.4
|
||||||
|
array.prototype.flat: 1.3.2
|
||||||
|
array.prototype.flatmap: 1.3.2
|
||||||
|
debug: 3.2.7
|
||||||
|
doctrine: 2.1.0
|
||||||
|
eslint: 8.57.0
|
||||||
|
eslint-import-resolver-node: 0.3.9
|
||||||
|
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||||
|
hasown: 2.0.2
|
||||||
|
is-core-module: 2.13.1
|
||||||
|
is-glob: 4.0.3
|
||||||
|
minimatch: 3.1.2
|
||||||
|
object.fromentries: 2.0.7
|
||||||
|
object.groupby: 1.0.2
|
||||||
|
object.values: 1.1.7
|
||||||
|
semver: 6.3.1
|
||||||
|
tsconfig-paths: 3.15.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.4.2):
|
/eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.4.2):
|
||||||
resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==}
|
resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
Reference in New Issue
Block a user