feat(listmonk): schedule weekly transactional emails
This commit is contained in:
parent
c1bd2aa9b8
commit
ffae0780e9
2 changed files with 73 additions and 19 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.env
|
.env
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.qodo
|
||||||
|
|
|
@ -10,6 +10,12 @@ export async function submitToListmonk(req, res) {
|
||||||
const listmonkBaseUrl = process.env.LISTMONK_BASE_URL;
|
const listmonkBaseUrl = process.env.LISTMONK_BASE_URL;
|
||||||
const listId = parseInt(process.env.LIST_ID, 10);
|
const listId = parseInt(process.env.LIST_ID, 10);
|
||||||
|
|
||||||
|
const welcomeTemplateId = parseInt(process.env.PRESET_CAMPAIGN_ID, 10);
|
||||||
|
const week1TemplateId = parseInt(process.env.TEMPLATE_ID_WEEK_1, 10);
|
||||||
|
const week2TemplateId = parseInt(process.env.TEMPLATE_ID_WEEK_2, 10);
|
||||||
|
const week3TemplateId = parseInt(process.env.TEMPLATE_ID_WEEK_3, 10);
|
||||||
|
const week4TemplateId = parseInt(process.env.TEMPLATE_ID_WEEK_4, 10);
|
||||||
|
|
||||||
// Encode username and password as base64
|
// Encode username and password as base64
|
||||||
const auth = Buffer.from(`${listmonkUsername}:${listmonkPassword}`).toString('base64');
|
const auth = Buffer.from(`${listmonkUsername}:${listmonkPassword}`).toString('base64');
|
||||||
|
|
||||||
|
@ -40,6 +46,50 @@ export async function submitToListmonk(req, res) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function scheduleTransactionalEmails(email, name, message, auth, baseUrl) {
|
||||||
|
const MAX_TIMEOUT_MS = 2147483647;
|
||||||
|
|
||||||
|
const SCHEDULES = [
|
||||||
|
{ delayMs: 7 * 24 * 60 * 60 * 1000, templateId: week1TemplateId }, // 1 week
|
||||||
|
{ delayMs: 14 * 24 * 60 * 60 * 1000, templateId: week2TemplateId }, // 2 weeks
|
||||||
|
{ delayMs: 21 * 24 * 60 * 60 * 1000, templateId: week3TemplateId }, // 3 weeks
|
||||||
|
{
|
||||||
|
delayMs: Math.min(28 * 24 * 60 * 60 * 1000, MAX_TIMEOUT_MS), // 4 weeks (capped)
|
||||||
|
templateId: week4TemplateId
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { delayMs, templateId } of SCHEDULES) {
|
||||||
|
setTimeout(async () => {
|
||||||
|
const payload = {
|
||||||
|
template_id: templateId,
|
||||||
|
subscriber_emails: [email],
|
||||||
|
from_email: "Janek <janek@melonion.me>",
|
||||||
|
data: { name, message }
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${baseUrl}/tx`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Basic ${auth}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
console.error(`Error sending email with template ${templateId}:`, await res.text());
|
||||||
|
} else {
|
||||||
|
console.log(`Email sent with template ${templateId}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error dispatching scheduled email for template ${templateId}:`, err);
|
||||||
|
}
|
||||||
|
}, delayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Add subscriber
|
// Add subscriber
|
||||||
const response = await fetchWithRetry(listmonkSubscriberUrl, {
|
const response = await fetchWithRetry(listmonkSubscriberUrl, {
|
||||||
|
@ -49,7 +99,7 @@ export async function submitToListmonk(req, res) {
|
||||||
'Authorization': `Basic ${auth}`
|
'Authorization': `Basic ${auth}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
},12);
|
}, 12);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorBody = await response.text();
|
const errorBody = await response.text();
|
||||||
|
@ -59,33 +109,36 @@ export async function submitToListmonk(req, res) {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('Subscriber added successfully:', result);
|
console.log('Subscriber added successfully:', result);
|
||||||
|
|
||||||
// Send transactional email
|
// Send welcome message immediately
|
||||||
const transactionalUrl = `${listmonkBaseUrl}/tx`;
|
const transactionalUrl = `${listmonkBaseUrl}/tx`;
|
||||||
const txPayload = {
|
const txPayload = {
|
||||||
template_id: parseInt(process.env.PRESET_CAMPAIGN_ID, 10),
|
template_id: welcomeTemplateId,
|
||||||
subscriber_emails: [ email ],
|
subscriber_emails: [email],
|
||||||
from_email: "Janek <janek@melonion.me>",
|
from_email: "Janek <janek@melonion.me>",
|
||||||
data: { name, message }
|
data: { name, message }
|
||||||
};
|
};
|
||||||
|
|
||||||
const txResponse = await fetchWithRetry(transactionalUrl, {
|
const txResponse = await fetchWithRetry(transactionalUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': `Basic ${auth}`
|
'Authorization': `Basic ${auth}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(txPayload)
|
body: JSON.stringify(txPayload)
|
||||||
}, 12);
|
}, 12);
|
||||||
|
|
||||||
if (!txResponse.ok) {
|
if (!txResponse.ok) {
|
||||||
const errorBody = await txResponse.text();
|
const errorBody = await txResponse.text();
|
||||||
throw new Error(`Listmonk TX error: ${txResponse.statusText}. ${errorBody}`);
|
throw new Error(`Listmonk TX error: ${txResponse.statusText}. ${errorBody}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dispatchResult = await txResponse.json();
|
const dispatchResult = await txResponse.json();
|
||||||
console.log('tx dispatched successfully:', dispatchResult);
|
console.log('Welcome email dispatched successfully:', dispatchResult);
|
||||||
|
|
||||||
res.status(200).json({ message: 'Subscription and welcome email sent successfully!', result });
|
// Schedule the remaining follow-up emails
|
||||||
|
await scheduleTransactionalEmails(email, name, message, auth, listmonkBaseUrl);
|
||||||
|
|
||||||
|
res.status(200).json({ message: 'Subscription and emails scheduled successfully!', result });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error submitting to Listmonk:', error);
|
console.error('Error submitting to Listmonk:', error);
|
||||||
|
|
Loading…
Add table
Reference in a new issue