feat(mailing): send transactional message instead of campaign

This commit is contained in:
ryan 2025-04-23 16:34:37 +03:00
parent 7c5074098c
commit ea28e6306d

View file

@ -1,10 +1,10 @@
import fetch from 'node-fetch'; 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) { export async function submitToListmonk(req, res) {
const { name, email, message } = req.body; 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 listmonkUsername = process.env.LISTMONK_USERNAME;
const listmonkPassword = process.env.LISTMONK_PASSWORD; const listmonkPassword = process.env.LISTMONK_PASSWORD;
const listmonkBaseUrl = process.env.LISTMONK_BASE_URL; const listmonkBaseUrl = process.env.LISTMONK_BASE_URL;
@ -13,7 +13,7 @@ export async function submitToListmonk(req, res) {
// 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');
console.log(`Sending request to Listmonk with URL: ${listmonkUrl}`); console.log(`Sending request to Listmonk with URL: ${listmonkSubscriberUrl}`);
const payload = { const payload = {
email, email,
@ -23,26 +23,26 @@ export async function submitToListmonk(req, res) {
fields: { message } 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) { async function fetchWithRetry(url, options, retries = 3) {
for (let i = 0; i < retries; i++) { for (let i = 0; i < retries; i++) {
console.log(`Attempt ${i + 1} sending request to ${url}`); console.log(`Attempt ${i + 1} sending request to ${url}`);
try { try {
const res = await fetch(url, options); const res = await fetch(url, options);
if (!res.ok) throw new Error(`HTTP ${res.status}`); if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res; return res;
} catch (err) { } catch (err) {
console.log(`Attempt ${i + 1} failed: ${err}`); console.log(`Attempt ${i + 1} failed: ${err}`);
if (i === retries - 1) throw err; if (i === retries - 1) throw err;
await new Promise(resolve => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));
} }
} }
} }
try { try {
// Add subscriber // Add subscriber
const response = await fetchWithRetry(listmonkUrl, { const response = await fetchWithRetry(listmonkSubscriberUrl, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -59,95 +59,31 @@ 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);
// Create a new campaign for the subscriber // Send transactional email
const createCampaign = async (subject, body) => { const transactionalUrl = `${listmonkBaseUrl}/tx`;
const createCampaignUrl = `${listmonkBaseUrl}/campaigns`; const txPayload = {
const campaignPayload = { template_id: parseInt(process.env.PRESET_CAMPAIGN_ID, 10),
name: `Welcome email for ${email}`, subscriber_emails: [ email ],
subject: subject, from_email: "Janek <janek@melonion.me>",
from_email: "Janek <janek@melonion.me>", data: { name, message }
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;
}; };
// Campaign subject and body content const txResponse = await fetchWithRetry(transactionalUrl, {
const subject = "👋 Welcome to the Progodyssey Family!"; method: 'POST',
const body = `
<h1>👋 Welcome to the Progodyssey Family, {{ .Subscriber.Name }}!</h1>
<p>Were 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.</p>
<p>Heres what you can expect in the coming weeks:</p>
<ul>
<li>1 <strong>Learning Opportunities:</strong> Access to tutorials, and hands-on projects to sharpen your skills.</li>
<li>2 <strong>Mentorship:</strong> Personal Guidance to help you navigate your journey.</li>
<li>3 <strong>Community:</strong> A supportive group of peers and mentors working together towards success.</li>
</ul>
<p>To kick things off, go through the Progodyssey handbook, pick a course and submit your reflection essay to <a href="mailto:reflection@progodyssey.com">reflection@progodyssey.com</a>.</p>
<p>Janeks Blog could also have some insight for you.</p>
<p><em>Encouragement:</em><br>
<em>"Success is the sum of small efforts repeated day in and day out."</em> <cite>Robert Collier</cite></p>
<p>Lets take the first step together!<br>
If you have any questions or need assistance, feel free to reply to this email or contact us at <a href="mailto:hello@progodyssey.com">hello@progodyssey.com</a></p>
<p>Looking forward to seeing you thrive,<br>
<strong>The Progodyssey Team</strong></p>
`;
// 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',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': `Basic ${auth}`, 'Authorization': `Basic ${auth}`
}, },
body: JSON.stringify(dispatchPayload), body: JSON.stringify(txPayload)
}); }, 12);
if (!dispatchResponse.ok) { if (!txResponse.ok) {
const errorBody = await dispatchResponse.text(); const errorBody = await txResponse.text();
console.error('Response from Listmonk (Dispatch):', errorBody); throw new Error(`Listmonk TX error: ${txResponse.statusText}. ${errorBody}`);
throw new Error(`Listmonk API error (Dispatch Campaign): ${dispatchResponse.statusText}. Response body: ${errorBody}`);
} }
const dispatchResult = await dispatchResponse.json(); const dispatchResult = await txResponse.json();
console.log('Campaign dispatched successfully:', dispatchResult); console.log('tx dispatched successfully:', dispatchResult);
res.status(200).json({ message: 'Subscription and welcome email sent successfully!', result }); res.status(200).json({ message: 'Subscription and welcome email sent successfully!', result });