Skip to content

Commit 7d55d0f

Browse files
authored
fix: improve unsubscribe link in email footer (#2646)
- Add clickable HTML link in default footer template instead of plain URL - Restructure buildRenderedContent to return bodyHtml and footerHtml separately - Apply link tracking only to body content, add footer AFTER tracking - This ensures unsubscribe link is not trackable and displays properly as "Click here to unsubscribe"
1 parent 3943938 commit 7d55d0f

File tree

1 file changed

+30
-28
lines changed
  • supabase/functions/email-campaigns

1 file changed

+30
-28
lines changed

supabase/functions/email-campaigns/index.ts

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,11 @@ function defaultFooterTemplate(ownerEmail: string): string {
355355
if (CAMPAIGN_COMPLIANCE_FOOTER) {
356356
return CAMPAIGN_COMPLIANCE_FOOTER;
357357
}
358-
return `${COMPLIANCE_SEPARATOR}\n\nYou received this email because ${ownerEmail} used leadminer.io to extract contacts from their mailbox. Try https://leadminer.io yourself.\n\n${UNSUBSCRIBE_TEXT_SUFFIX}: {{unsubscribeUrl}}`;
358+
return `${COMPLIANCE_SEPARATOR}
359+
360+
You received this email because ${ownerEmail} used leadminer.io to extract contacts from their mailbox. Try https://leadminer.io yourself.
361+
362+
<p><a href="{{unsubscribeUrl}}">${UNSUBSCRIBE_TEXT_SUFFIX}</a></p>`;
359363
}
360364

361365
function ensureUnsubscribeText(
@@ -850,13 +854,14 @@ function buildRenderedContent(
850854
payload.unsubscribeUrl,
851855
);
852856

853-
const html = payload.plainTextOnly ? "" : `${renderedBodyHtml}${footerHtml}`;
857+
const html = payload.plainTextOnly ? "" : renderedBodyHtml;
854858
const text = `${renderedBodyText}\n\n${footerText}`.trim();
855859
const subject = renderTemplate(payload.subjectTemplate, contact, extra);
856860

857861
return {
858862
subject,
859-
html,
863+
bodyHtml: html,
864+
footerHtml,
860865
text,
861866
};
862867
}
@@ -1135,7 +1140,8 @@ app.post("/campaigns/preview", authMiddleware, async (c: Context) => {
11351140
eligibleContacts[Math.floor(Math.random() * eligibleContacts.length)];
11361141
const {
11371142
subject: renderedSubject,
1138-
html,
1143+
bodyHtml,
1144+
footerHtml,
11391145
text,
11401146
} = buildRenderedContent(randomContact, {
11411147
subjectTemplate: subject,
@@ -1154,17 +1160,13 @@ app.post("/campaigns/preview", authMiddleware, async (c: Context) => {
11541160

11551161
try {
11561162
const from = `"${escapeHtml(senderName)}" <${senderEmail}>`;
1157-
await sendEmail(
1158-
ownerEmail,
1159-
`[Preview] ${renderedSubject}`,
1160-
plainTextOnly ? "" : html,
1161-
{
1162-
from,
1163-
replyTo: ownerEmail,
1164-
text,
1165-
transport: transportBySender[senderEmail] ?? undefined,
1166-
},
1167-
);
1163+
const finalHtml = plainTextOnly ? "" : bodyHtml + footerHtml;
1164+
await sendEmail(ownerEmail, `[Preview] ${renderedSubject}`, finalHtml, {
1165+
from,
1166+
replyTo: ownerEmail,
1167+
text,
1168+
transport: transportBySender[senderEmail] ?? undefined,
1169+
});
11681170
return c.json({
11691171
msg: "Preview sent successfully",
11701172
selectedContactEmail: randomContact.email,
@@ -1732,7 +1734,8 @@ app.post(
17321734

17331735
const {
17341736
subject: renderedSubject,
1735-
html,
1737+
bodyHtml,
1738+
footerHtml,
17361739
text,
17371740
} = buildRenderedContent(snapshot, {
17381741
subjectTemplate: campaign.subject,
@@ -1755,22 +1758,21 @@ app.post(
17551758
campaign.id,
17561759
recipient.id,
17571760
recipient.open_token,
1758-
html,
1761+
bodyHtml,
17591762
campaign.track_click,
17601763
campaign.track_open,
17611764
);
17621765

1763-
await sendEmail(
1764-
recipient.contact_email,
1765-
renderedSubject,
1766-
campaign.plain_text_only ? "" : htmlWithTracking,
1767-
{
1768-
from: `"${escapeHtml(campaign.sender_name)}" <${campaign.sender_email}>`,
1769-
replyTo: campaign.reply_to,
1770-
text,
1771-
transport: senderTransport,
1772-
},
1773-
);
1766+
const finalHtml = campaign.plain_text_only
1767+
? ""
1768+
: htmlWithTracking + footerHtml;
1769+
1770+
await sendEmail(recipient.contact_email, renderedSubject, finalHtml, {
1771+
from: `"${escapeHtml(campaign.sender_name)}" <${campaign.sender_email}>`,
1772+
replyTo: campaign.reply_to,
1773+
text,
1774+
transport: senderTransport,
1775+
});
17741776

17751777
await supabaseAdmin
17761778
.schema("private")

0 commit comments

Comments
 (0)