From fdcf390d48e9fe0a7180335a61ea2bd25dee0e8d Mon Sep 17 00:00:00 2001 From: 2ManyProjects Date: Thu, 1 May 2025 22:22:58 -0500 Subject: [PATCH] added personalization to email campaigns --- backend/src/routes/emailCampaignsAdmin.js | 41 ++++++++++++++++--- .../pages/Admin/EmailCampaignEditorPage.jsx | 8 +++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/backend/src/routes/emailCampaignsAdmin.js b/backend/src/routes/emailCampaignsAdmin.js index 9d6152f..c703e05 100644 --- a/backend/src/routes/emailCampaignsAdmin.js +++ b/backend/src/routes/emailCampaignsAdmin.js @@ -540,7 +540,6 @@ router.post('/:id/send', async (req, res, next) => { }).catch(err => { console.error(`Error sending campaign ${id}:`, err); }); - https://click.pstmrk.it/3/localhost%3A3000%2Fapi%2Fsubscribers%2Funsubscribe%3Ftoken%3De5b3b22c-ba7f-4684-afce-bd998d45f0b1/aODm/yg69AQ/AQ/030c5f0a-b979-4327-a121-9c91eeb9eb40/1/tDsgHryVEs res.json({ success: true, message: `Campaign scheduled for sending to ${subscribers.length} recipients`, @@ -580,12 +579,16 @@ async function sendCampaignEmails(campaignId, campaign, subscribers) { // Send emails in parallel within each batch await Promise.all(batch.map(async (subscriber) => { try { + let personalizedContent = personalizeContent(campaign.content, subscriber); + let personalizedSubject = personalizeContent(campaign.subject, subscriber); + let personalizedPreheader = campaign.preheader ? personalizeContent(campaign.preheader, subscriber) : ''; + await emailService.sendCampaignEmail({ to: subscriber.email, - subject: campaign.subject, - preheader: campaign.preheader || '', + subject: personalizedSubject, + preheader: personalizedPreheader, from: `${campaign.from_name} <${campaign.from_email}>`, - content: campaign.content, + content: personalizedContent, campaignId: campaignId, subscriberId: subscriber.id }); @@ -1027,4 +1030,32 @@ async function sendCampaignEmails(campaignId, campaign, subscribers) { }); return router; -}; \ No newline at end of file +}; + + +/** + * Replace personalization variables in content + * + * @param {string} content - The email content + * @param {Object} subscriber - The subscriber object + * @returns {string} - Content with variables replaced + */ +function personalizeContent(content, subscriber) { + if (!content) return ''; + + let personalized = content; + + if (personalized.includes('{{first_name}}')) { + personalized = personalized.replace(/{{first_name}}/g, subscriber.first_name || ''); + } + + if (personalized.includes('{{last_name}}')) { + personalized = personalized.replace(/{{last_name}}/g, subscriber.last_name || ''); + } + + if (personalized.includes('{{email}}')) { + personalized = personalized.replace(/{{email}}/g, subscriber.email || ''); + } + + return personalized; +} \ No newline at end of file diff --git a/frontend/src/pages/Admin/EmailCampaignEditorPage.jsx b/frontend/src/pages/Admin/EmailCampaignEditorPage.jsx index e4f109e..fd0c3b7 100644 --- a/frontend/src/pages/Admin/EmailCampaignEditorPage.jsx +++ b/frontend/src/pages/Admin/EmailCampaignEditorPage.jsx @@ -362,7 +362,13 @@ const EmailCampaignEditor = () => {
  • Keep your message clear and concise
  • Include a strong call-to-action
  • Test your email on different devices before sending
  • -
  • Personalize content where possible using variables like {`{{first_name}}`}
  • +
  • Personalize content where possible using user variables (including the curly braces), currently we support: +
      +
    1. {`{{first_name}}`}
    2. +
    3. {`{{last_name}}`}
    4. +
    5. {`{{email}}`}
    6. +
    +
  • Add alt text to images for better accessibility