Skip to content

HEADLESS senders can't get List-Unsubscribe with their own list-management links (follow-up to #411) #421

Description

@chamby

Follow-up on the #411 header work (commit 8f23d8a) — reading the code, not something we've wired up yet, so apologies if I've misread.

The one-click List-Unsubscribe pair is gated on bodyHasListManagementLink, which only matches Plunk's own /unsubscribe/{id} | /manage/{id}. So a HEADLESS sender who ships their own opt-out URL gets the bulk trio (via isCampaign) but never the List-Unsubscribe pair — and the emitted value is hardcoded to DASHBOARD_URI regardless. That inverts what HEADLESS is for: bring-your-own list management gets you every header except the one that matters for one-click. Campaigns can't work around it either — no headers field like /v1/send has.

The part that seems off: you already ship detectUnsubscribeSignal (matches {{unsubscribeUrl}}/{{manageUrl}}, unsubscribe-keyword hrefs, anchor text) to tell HEADLESS authors they have an opt-out. But header emission uses the stricter bodyHasListManagementLink. So a template can pass the author-facing "you have an unsubscribe mechanism" check and still emit no List-Unsubscribe header — the two functions disagree on what counts as list management.

Would a per-send/per-campaign listUnsubscribe (https one-click + optional mailto:) that emits the pair pointing at the sender's own endpoint, independent of class and body detection, be in scope? Failing that, having the header path honor the same signal detectUnsubscribeSignal already recognizes would close most of the gap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions