diff --git a/backend/campaigns/migrations/0010_merge_0009_campaign_cached_counters_0009_campaignlead_bounce_metadata.py b/backend/campaigns/migrations/0010_merge_0009_campaign_cached_counters_0009_campaignlead_bounce_metadata.py
new file mode 100644
index 0000000..611e30b
--- /dev/null
+++ b/backend/campaigns/migrations/0010_merge_0009_campaign_cached_counters_0009_campaignlead_bounce_metadata.py
@@ -0,0 +1,13 @@
+# Generated by Django 5.0.14 on 2026-06-22
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("campaigns", "0009_campaign_cached_counters"),
+ ("campaigns", "0009_campaignlead_bounce_metadata"),
+ ]
+
+ operations = []
diff --git a/backend/campaigns/tests.py b/backend/campaigns/tests.py
index 1d96075..ca9ded8 100644
--- a/backend/campaigns/tests.py
+++ b/backend/campaigns/tests.py
@@ -1344,6 +1344,35 @@ def test_unsubscribe_view_rejects_invalid_token(self):
lead.refresh_from_db()
self.assertFalse(lead.global_unsubscribe)
+ def test_unsubscribe_view_uses_organization_branding(self):
+ branded_org = Organization.objects.create(
+ name='Northwind',
+ unsubscribe_title='Stay connected with Northwind',
+ unsubscribe_message='You can change your preferences any time from our support team.',
+ brand_logo_url='https://cdn.example.com/northwind-logo.png',
+ )
+ branded_user = User.objects.create_user(
+ email='owner@northwind.test',
+ password='StrongPass123!',
+ organization=branded_org,
+ role='ADMIN',
+ )
+ lead = Lead.objects.create(
+ organization=branded_org,
+ email='unsubscribe@northwind.test',
+ )
+ token = generate_unsubscribe_token(lead.id)
+
+ self.client.force_authenticate(branded_user)
+ response = self.client.get(f'/api/v1/unsubscribe/{lead.id}/{token}/')
+
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ html = response.content.decode('utf-8')
+ self.assertIn('Stay connected with Northwind', html)
+ self.assertIn('You can change your preferences any time from our support team.', html)
+ self.assertIn('https://cdn.example.com/northwind-logo.png', html)
+ self.assertIn('Northwind', html)
+
def test_send_email_step_skips_unsubscribed_leads(self):
campaign = Campaign.objects.create(
organization=self.organization,
diff --git a/backend/campaigns/views.py b/backend/campaigns/views.py
index 2a11bf0..774c2e4 100644
--- a/backend/campaigns/views.py
+++ b/backend/campaigns/views.py
@@ -1,6 +1,7 @@
import logging
+from html import escape
import urllib.parse
from django.core.signing import Signer, BadSignature
from django.http import HttpResponseRedirect, HttpResponseBadRequest
@@ -718,21 +719,56 @@ def _build_fallback_content(self, request):
from .utils import verify_unsubscribe_token
-def _unsubscribe_page(title, message, extra_html=''):
+def _build_unsubscribe_brand_block(organization):
+ org_name = escape((organization.name or 'LeadOrbit').strip())
+ logo_url = (organization.brand_logo_url or '').strip()
+
+ if logo_url:
+ logo_html = (
+ f''
+ )
+ else:
+ logo_letter = escape((organization.name or 'L').strip()[:1] or 'L')
+ logo_html = f'
{message}
{extra_html}{brand_message}
{extra_html}If you received this link by mistake, no further action is needed.
', + '