Bcc Guard

Shows the To line as each recipient will see it, so a group email doesn't expose everyone's names and addresses to each other.

StopsRecipients see each other's addresses

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/bcc-guard.json

The files land in your project. They're yours to edit.

Usage

bcc-guard-usage.tsx
import { BccGuard, type Recipients } from "@/components/ui/bcc-guard"

<BccGuard
  defaultValue={START}
  internalDomains={["soho-clinic.nhs.uk"]}
  from="news@soho-clinic.nhs.uk"
  subject={subject}
  onSend={async (v, mode) => {
    await new Promise((r) => setTimeout(r, 600))
    setSent(mode === "individually" ? `Queued ${list.length} separate emails, one per person.` : `Sent to ${v.to.length + v.cc.length + v.bcc.length} recipients.`)
  }}
/>

What it catches

  • Recipients who can see each other's addresses on To or Cc
  • Addresses or display names that give away a person's name, and outside companies
  • Subjects or bodies with terms that make being on the list sensitive
  • Sending while addresses still show, with options to move them to Bcc or send one email each

Props

BccGuard props
PropTypeDefault
value

Controlled recipients.

Recipients—
defaultValue

Initial recipients when uncontrolled.

Recipients—
onValueChange

Fires with the new recipients after a fix or an undo.

(value: Recipients) => void—
internalDomains

Your own organisation's domains; colleagues there may see each other.

string[]—
from

The sender's address. When every recipient moves to Bcc it fills the empty To line.

string—
subject

Subject and body, scanned for terms that make the list itself sensitive.

string—
body

Email body, scanned for sensitive terms.

string—
sensitiveTerms

Terms that make membership of the list sensitive. Replaces the default list; spread DEFAULT_SENSITIVE_TERMS to extend it.

string[]—
exposeAt

How many outside organisations seeing each other counts as exposed (default 3; 2 on a sensitive email).

number—
onSend

Sends the email. `individually` asks for one message per recipient. May return a Promise.

(value: Recipients, mode: "together" | "individually") => void | Promise<void>—
previewCount

Addresses shown in the preview before "+N more". Default 3.

number3
messages

Override any visible string.

Partial<Messages>—

* required. Also accepts the native props of <section> (className, aria-*, data-*…), passed through to it.

Accessibility

  • The preview is labelled by its heading (aria-labelledby)
  • Focus moves to the next sensible action (Move to Bcc, then Send)
  • The second-press warning uses role="alert" and the Send button is described by it
  • Status is announced in a role="status" region; motion respects prefers-reduced-motion

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Sensitive-term matching uses a word list (replaceable); other sensitive contexts are missed
  • Internal vs outside is decided only by the internalDomains you pass
  • It cannot stop replies-all or forwards after sending

What it stops

Recipients see each other's addresses

Also known as

bcc · cc · to field · recipients · newsletter · mailing list · compose · mail merge

Field type

Dependencies

Pairs well with