Logotipo Hedhog

Get Hedhog updates in your inbox

New releases, fresh recipes, and breaking changes — no spam.

Campaign Submodule

unsubscribes

Token-based public unsubscribe flow plus an admin listing of all unsubscribe records.

Source path: libraries/campaign/src/services/campaign-unsubscribe.service.ts

Module file: campaign.module.ts

Introduction

The Unsubscribes submodule implements the opt-out half of email compliance: a signed, single-use-confirmable token embedded in every sent campaign email's `{{unsubscribeUrl}}` placeholder, and the public landing-page flow that resolves it. `CampaignUnsubscribeService.generateUnsubscribeToken` is called by CampaignEmailWorkerService while building each message's content, creating a `campaign_unsubscribe` row keyed by a random token and linked to the campaign, recipient, and message it was generated for, with a `scope` (defaulting to `all_campaigns`) that determines how broad the eventual opt-out will be.

`GET /campaign/unsubscribe/:token` is the public, unauthenticated endpoint the landing page calls to render a confirmation screen — it returns only non-sensitive fields (email, scope, whether it was already processed) and never the underlying recipient or campaign IDs. `POST /campaign/unsubscribe/:token` is the actual confirmation action, also public, and is fully idempotent: calling it again after a successful unsubscribe simply returns `alreadyUnsubscribed: true` without side effects. On first confirmation it does five things in sequence: marks the unsubscribe record confirmed (storing the requester's IP and user-agent), flips the linked recipient(s) to `status: unsubscribed`, marks the specific message (or any still-active message for that email in that campaign) as `unsubscribed`, increments the campaign's `total_unsubscribed` counter, writes an `unsubscribed` campaign event, and — only when `scope` is `all_campaigns` — adds the email to the global Suppression list with `reason: unsubscribe`, which is what actually prevents future campaigns from emailing that address again.

`GET /campaign/unsubscribes` is the admin-facing counterpart: a simple paginated, search-filterable list of every unsubscribe record ever generated, regardless of whether it was ever confirmed — useful for auditing how many recipients received an unsubscribe link versus how many actually used it.

HTTP Endpoints

3 endpoints

Admin paginated list of all unsubscribe records, confirmed or not.

Query
page, pageSize, search

Get unsubscribe landing page data from a signed token. Returns the email, scope, and confirmation state for the confirmation UI.

Params
token (string)

Confirm an unsubscribe. Idempotent. Records IP and user-agent, marks the recipient(s) and message as unsubscribed, increments campaign counters, and — for "all_campaigns" scope — adds the email to the global suppression list.

Params
token (string)