From ea28e6306d71d72868c7b3b2fa87b78e91c57c03 Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 23 Apr 2025 16:34:37 +0300 Subject: [PATCH] feat(mailing): send transactional message instead of campaign --- src/formHandler.js | 136 ++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 100 deletions(-) diff --git a/src/formHandler.js b/src/formHandler.js index f97f594..1eb940a 100644 --- a/src/formHandler.js +++ b/src/formHandler.js @@ -1,10 +1,10 @@ import fetch from 'node-fetch'; -// Function to handle form submission and interact with Listmonk +// Function to handle form submission and send transactional email via Listmonk export async function submitToListmonk(req, res) { const { name, email, message } = req.body; - const listmonkUrl = process.env.LISTMONK_URL; + const listmonkSubscriberUrl = process.env.LISTMONK_URL; const listmonkUsername = process.env.LISTMONK_USERNAME; const listmonkPassword = process.env.LISTMONK_PASSWORD; const listmonkBaseUrl = process.env.LISTMONK_BASE_URL; @@ -13,7 +13,7 @@ export async function submitToListmonk(req, res) { // Encode username and password as base64 const auth = Buffer.from(`${listmonkUsername}:${listmonkPassword}`).toString('base64'); - console.log(`Sending request to Listmonk with URL: ${listmonkUrl}`); + console.log(`Sending request to Listmonk with URL: ${listmonkSubscriberUrl}`); const payload = { email, @@ -23,26 +23,26 @@ export async function submitToListmonk(req, res) { fields: { message } }; - console.log('Sending request to Listmonk with payload:', payload); + console.log('Sending subscriber to Listmonk with payload:', payload); async function fetchWithRetry(url, options, retries = 3) { for (let i = 0; i < retries; i++) { - console.log(`Attempt ${i + 1} sending request to ${url}`); - try { - const res = await fetch(url, options); - if (!res.ok) throw new Error(`HTTP ${res.status}`); - return res; - } catch (err) { - console.log(`Attempt ${i + 1} failed: ${err}`); - if (i === retries - 1) throw err; - await new Promise(resolve => setTimeout(resolve, 500)); - } + console.log(`Attempt ${i + 1} sending request to ${url}`); + try { + const res = await fetch(url, options); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + return res; + } catch (err) { + console.log(`Attempt ${i + 1} failed: ${err}`); + if (i === retries - 1) throw err; + await new Promise(resolve => setTimeout(resolve, 500)); + } } - } - + } + try { // Add subscriber - const response = await fetchWithRetry(listmonkUrl, { + const response = await fetchWithRetry(listmonkSubscriberUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -59,95 +59,31 @@ export async function submitToListmonk(req, res) { const result = await response.json(); console.log('Subscriber added successfully:', result); - // Create a new campaign for the subscriber - const createCampaign = async (subject, body) => { - const createCampaignUrl = `${listmonkBaseUrl}/campaigns`; - const campaignPayload = { - name: `Welcome email for ${email}`, - subject: subject, - from_email: "Janek ", - body: body, - type: "regular", - to_emails: [email], - lists: [listId], - content_type: "richtext", - status: "scheduled", - schedule: new Date().toISOString() - }; - - const response = await fetch(createCampaignUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Basic ${auth}`, - }, - body: JSON.stringify(campaignPayload), - }); - - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Listmonk API error (Create Campaign): ${response.statusText}. Response body: ${errorBody}`); - } - - const result = await response.json(); - return result.data.id; + // Send transactional email + const transactionalUrl = `${listmonkBaseUrl}/tx`; + const txPayload = { + template_id: parseInt(process.env.PRESET_CAMPAIGN_ID, 10), + subscriber_emails: [ email ], + from_email: "Janek ", + data: { name, message } }; - - // Campaign subject and body content - const subject = "👋 Welcome to the Progodyssey Family!"; - const body = ` -

👋 Welcome to the Progodyssey Family, {{ .Subscriber.Name }}!

- -

We’re thrilled to have you as part of the Progodyssey Traineeship journey! 🎉 - This program is designed to equip you with the skills, experience, and network to thrive in the tech world and beyond.

- -

Here’s what you can expect in the coming weeks:

-
    -
  • 1️⃣ Learning Opportunities: Access to tutorials, and hands-on projects to sharpen your skills.
  • -
  • 2️⃣ Mentorship: Personal Guidance to help you navigate your journey.
  • -
  • 3️⃣ Community: A supportive group of peers and mentors working together towards success.
  • -
- -

To kick things off, go through the Progodyssey handbook, pick a course and submit your reflection essay to reflection@progodyssey.com.

-

Janek’s Blog could also have some insight for you.

- -

Encouragement:
- "Success is the sum of small efforts repeated day in and day out."Robert Collier

- -

Let’s take the first step together!
- If you have any questions or need assistance, feel free to reply to this email or contact us at hello@progodyssey.com

- -

Looking forward to seeing you thrive,
- The Progodyssey Team

- `; - - // 1. Create campaign - const newCampaignId = await createCampaign(subject, body); - console.log(`Created new campaign with ID: ${newCampaignId}`); - - // 2. Dispatch campaign - const dispatchUrl = `${listmonkBaseUrl}/campaigns/${newCampaignId}/status`; - const dispatchPayload = { - status: 'running' - }; - - const dispatchResponse = await fetch(dispatchUrl, { - method: 'PUT', + + const txResponse = await fetchWithRetry(transactionalUrl, { + method: 'POST', headers: { 'Content-Type': 'application/json', - 'Authorization': `Basic ${auth}`, + 'Authorization': `Basic ${auth}` }, - body: JSON.stringify(dispatchPayload), - }); - - if (!dispatchResponse.ok) { - const errorBody = await dispatchResponse.text(); - console.error('Response from Listmonk (Dispatch):', errorBody); - throw new Error(`Listmonk API error (Dispatch Campaign): ${dispatchResponse.statusText}. Response body: ${errorBody}`); + body: JSON.stringify(txPayload) + }, 12); + + if (!txResponse.ok) { + const errorBody = await txResponse.text(); + throw new Error(`Listmonk TX error: ${txResponse.statusText}. ${errorBody}`); } - const dispatchResult = await dispatchResponse.json(); - console.log('Campaign dispatched successfully:', dispatchResult); + const dispatchResult = await txResponse.json(); + console.log('tx dispatched successfully:', dispatchResult); res.status(200).json({ message: 'Subscription and welcome email sent successfully!', result });