# Blocking a sender

A block is a `connect_memory` row against the contact, carrying `block:<channel>` **in its tag list**. It is deliberately not a column on the contact. Because `directives()` reads only tags, it is found wherever that person is considered — a different channel, a different thread, a conversation that has not happened yet — and it is undone by forgetting the row.

- **Status:** Available
- **Audience:** both
- **Channels:** email
- **In the app:** #/inbox, #/relationships
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/email/blocking/

## Why a tag and not a column

The obvious design is `contacts.blocked = true`. It is also the design that breaks first, in three predictable ways: it stops a person rather than a person on a channel, it lives on one record so it has to be re-checked by every path that might send something, and it carries no reason, no author and no date.

Connect stores it where directions already live. Memory resolves narrowest-first over four tiers — workspace, channel, endpoint, contact — and `directives()` pulls out the ones that constrain behaviour. It reads **only the tag list**, never the body. So a row whose tags include `block:email` is a machine-readable instruction; the body of the same row is free to hold the human reason, and nothing depends on parsing it.

> **Careful** This is the failure mode to avoid when creating one by hand: writing the intention as the body of a memory does nothing at all. The tag is the instruction. The body is a note to the next person.

## What one tag covers

| Tag | Stops | Leaves alone |
|---|---|---|
| `block:email` | Email to them | Their WhatsApp, their calls |
| `block:whatsapp` | WhatsApp to them | Their email |
| `block:voice` | Outbound voice to them | Written channels |
| `block:sms` | SMS to them | Everything else |

These are per channel because that is how the complaint usually arrives — "stop emailing me, ring me instead" is a real and reasonable request, and a single global switch cannot express it. Where the person wants nothing at all, the right record is a do-not-contact entry, described on [Do not contact](/docs/email/dnc/), which is checked in the compliance path rather than the memory path.

Because the row sits on the person rather than the thread, it survives the thread being closed, a new message arriving from them months later, and them being reached through a different mailbox.

## Placing and lifting one

1. Use the block action on the contact panel or the conversation.
   - Result: A `connect_memory` row is written against that person with the channel's tag, and the reason you type becomes the body.
2. Check it took, in the memory viewer for that person.
   - Result: The row is visible at the contact tier with its tag. One you cannot see in the viewer was not written.
3. To lift it, forget the row.
   - Result: The directive stops being returned, and they are eligible again on that channel from the next piece of work onwards.

> **Note** Lifting one is not the same as clearing a suppression, an unsubscribe or a do-not-contact entry. Those are compliance records with their own rules, and the Connect Assistant cannot clear a do-not-contact entry at all — its rights are narrower than a person's on purpose.

## What the other person experiences

Nothing. There is no bounce, no automatic notice and no change to what they can send you. Their mail still arrives, is still canonicalised into a thread and is still readable. The directive governs what goes out, not what comes in — which is the behaviour you want, since the message that finally explains the misunderstanding is usually the one you would have cut yourself off from.

On your side, a thread with a blocked person shows the directive rather than quietly producing nothing, so "why has this not been answered" has an answer on the screen where the question is asked.

## Questions

### Does blocking stop their messages reaching me?

No. Inbound mail is unaffected: it syncs, threads and appears in Conversations as usual. If you want it out of your working list as well, delete the thread — that mark is separate and covered on [Triage and priority](/docs/email/triage/).

### Can the Assistant block someone for me?

The Assistant can write and forget memories with `remember` and `forget`, so one placed that way is an ordinary memory row like any other. What it cannot do is clear a do-not-contact entry, which is a compliance record rather than a memory.

### Why did a message still go out to someone I blocked?

Two causes are worth checking in this order: the tag was on the wrong channel — `block:whatsapp` does not stop email — or it was written as body text rather than as a tag, in which case `directives()` never saw it. The memory viewer shows both immediately.

## Related

- [Memory in Connect](https://connectbyjbrh.com/docs/memory/)
- [Do not contact](https://connectbyjbrh.com/docs/email/dnc/)
- [The suppression list](https://connectbyjbrh.com/docs/email/suppression-list/)
- [Triage and priority](https://connectbyjbrh.com/docs/email/triage/)
- [Structured business memory instead of a longer prompt](https://connectbyjbrh.com/research/structured-business-memory/)

## What this page is based on

- CHANNELS.md §1 — triage and blocking
- GENERAL.md §6 — memory tiers and `directives()`
- `backend/app/connect_memory.py` — `directives()`
- Connect capability registry (docs-source/facts.py) — `block_directive`
