Skip to content

Extend the account email-preference center to event, Slack, and newsletter purposes #227

Description

@alexeygrigorev

Parent decision: #22
Related: #21, #50, #225

Context

Decision #11 (resolved in #22) authorizes the email-purpose catalog. Recipients control optional
mail through the existing account-settings preference mechanism; this issue extends that mechanism
and the Relay delivery checks rather than introducing a second preference system.

Product contract

Preference categories

  • Event email is optional and applies only to a recipient registered for the relevant event. The
    recipient may opt out of all event mail, including verification, confirmation, cancellation,
    reschedule, reminder, and other event-lifecycle messages. Event preference is separate from
    newsletter/marketing preference.
  • Marketing/newsletter is a separate optional category. New member/account signup defaults it on,
    but an unverified new account is not a newsletter recipient. The recipient can unsubscribe later.
  • Slack access is a one-time requested-service message, not a recurring preference category. It has
    no preference toggle and is not sent again automatically. Account verification and password
    recovery are also non-optional security messages.

Audiences and onboarding

  • A new account receives email verification first. After successful verification, it receives one
    Slack join-link email, and the current link is also available in the authenticated member area.
  • Legacy/imported contacts bypass the new-account verification-to-Slack sequence and do not receive
    an automatic Slack message merely because they were imported.
  • Newsletter delivery targets verified contacts plus the explicit legacy/imported audience, which is
    treated as assumed verified for newsletter delivery. A new account must verify before entering the
    verified audience.
  • An identifiable logged-in interaction or a recipient-specific newsletter-link interaction may
    move a legacy contact from legacy to verified. This is not a newsletter delivery prerequisite
    and does not trigger another email. A bare anonymous visit does not identify a contact and does
    not change status.

Mailchimp reconciliation

Mailchimp is authoritative for legacy marketing subscription state. Provide two separate,
idempotent import operations:

  • subscribed list: turn the matched legacy marketing preference on;
  • unsubscribed list: turn the matched marketing preference off.

The operations affect only the marketing/newsletter preference. A contact absent from both lists
keeps the current platform preference. The supported input lists are assumed clean and mutually
exclusive; overlap precedence is out of scope.

Unsubscribe and link safety

  • A visible body/footer unsubscribe link opens the website preference page. The recipient unticks
    unwanted categories and submits; the initial GET is non-mutating.
  • A supported Gmail/email-header one-click action may immediately and idempotently disable only the
    category represented by that message, without changing unrelated categories.
  • Preference and newsletter-attribution links use opaque, recipient- and purpose-scoped, expiring,
    replay-safe tokens. Raw email addresses never appear in URLs or logs. A newsletter token is for
    recipient attribution and legacy-status promotion, not an additional verification gate.

Ask

Extend the existing preference-toggle mechanism and shared application services to add event and
marketing/newsletter categories, enforce them before Relay submission, support the preference-center
unsubscribe flow plus the email-header one-click path, and add the two Mailchimp legacy preference
imports. Do not add a recurring Slack toggle or a separate preference implementation.

Acceptance criteria

  • Existing account settings exposes event and marketing/newsletter preferences without creating
    a parallel toggle system; existing course categories remain unchanged.
  • Event mail is sent only to an active registrant for the relevant event and only while the
    event preference is enabled. Opting out suppresses every event-lifecycle message.
  • Marketing/newsletter sends are made only to verified contacts and the explicit legacy audience;
    unverified new accounts are excluded.
  • Preference state is enforced before Relay submission, with idempotent suppression and no
    changes to unrelated categories.
  • A body/footer unsubscribe link opens the preference page, where the recipient can untick
    categories and submit; the initial GET does not mutate state.
  • The supported email-header one-click action disables only the represented optional category,
    immediately and idempotently.
  • New signup sends verification before the one-time Slack join-link delivery; the link is also
    available in the authenticated member area, and retries do not create automatic duplicates.
  • Legacy/imported contacts bypass the new-signup sequence; identifiable account/newsletter
    interactions may promote legacy to verified, while anonymous visits do not.
  • Subscribed and unsubscribed Mailchimp imports independently turn the legacy marketing
    preference on/off; absent contacts preserve the current platform preference. List overlap is
    outside the supported input contract.
  • Preference/attribution tokens are opaque, scoped, expiring, replay-safe, redacted, and never
    expose raw email addresses in URLs or logs.
  • All email mutations use the existing application services, one durable EmailDelivery intent
    and after-commit job, Relay routing, and the established idempotency/reconciliation model.

Dependencies

Depends on #22 (resolved). Coordinates with #21/#50 for Relay purpose/template identifiers and with
#225 for the shared preference-center surface (GA4 remains a separate purpose).

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