The **Classification Rules** page controls which signals put an address on your [Undeliverable List](/reports/undeliverable-list). Different operators have legitimately different tolerance for false positives — a bank cares about every legitimate send, a marketing team cares more about list hygiene — so the rules are configurable per organization.



You can reach this page from the **Configure rules** button in the top-right of the Undeliverable list, or directly at `/undeliverable/rules`.

## Profiles

Pick a profile to apply the recommended defaults. The "Custom" indicator appears automatically when your individual rule settings don't match any preset.

| Profile | What it includes | Typical fit |
|---------|------------------|-------------|
| **Strict** | Locked rules only — permanent bounces, complaints, rejects | Banks, strictly transactional senders. Lowest false-positive risk. |
| **Standard** *(default)* | Locked rules + repeated transient bounces (3 events in 30 days) | Most orgs. Catches Mimecast / Office 365 / Proofpoint accept-then-NDR patterns. |
| **Aggressive** | Standard + undetermined (2 in 14 days) + soft-bounce accumulation (5 in 14 days) | Marketing or bulk senders where bounce-rate reputation is existential. |
| **Custom** | Whatever you've configured in the Advanced section | Auto-selected when knobs deviate from a preset. |

Picking a named profile resets every configurable rule to that profile's defaults. If you have unsaved changes, SendOps will confirm before discarding them.

## Always-on (locked) rules

Three rules cannot be disabled. They are the core compliance and correctness signals.

- **Permanent bounces** (any sub-type — `NoEmail`, `General`, `Suppressed`, `OnAccountSuppressionList`, etc.) — the AWS-confirmed signal that an address is dead.
- **Complaints** — required for compliance (CAN-SPAM, CASL, GDPR). Disabling these would be a legal footgun.
- **Rejects** — SES already refused the send. Suppressing is correctness, not policy.

These appear in the Advanced section as read-only with a lock icon.

## Configurable rules

Each configurable rule has two knobs:

- **Events** — how many qualifying events must occur (integer, 1–100)
- **Within (days)** — how many days back to look (integer, 1–365)

When at least that many qualifying events have happened for an address inside the **Within (days)** window ending right now, the rule fires.

### Repeated transient bounces

Catches the receiving MTA returning `250 OK` to SES at SMTP time, then asynchronously generating a Non-Delivery Report. SES emits this as `Bounce / Transient / General` even though the address is effectively permanently undeliverable. Mimecast, Office 365, and Proofpoint all behave this way.

- **Counts**: Transient bounces with sub-type `General` only
- **Default**: 3 events in 30 days, on under Standard

This is the rule most likely to recover undelivered addresses from your real traffic. For one early customer it surfaced 116 missing addresses that were generating thousands of bounces but never appearing on the Strict-only list.

### Undetermined bounces

SES couldn't classify the bounce. Rare (~1% of events) but real — and sometimes the only signal you get for a domain that intermittently refuses mail.

- **Counts**: Bounces with `bounceType = Undetermined`
- **Default**: 2 events in 14 days, off

Turning this on cleans the long tail at the cost of occasional false positives where a transient infrastructure problem produced the events.

### Soft-bounce accumulation

For mailboxes that keep failing for the same reason — quotas, message size, content rejection. The address isn't dead, but continuing to send is wasted budget and bad reputation.

- **Counts**: Transient bounces with sub-type `MailboxFull`, `MessageTooLarge`, `ContentRejected`, or `AttachmentRejected`
- **Default**: 5 events in 14 days, off

`ChannelLimitExceeded` is intentionally excluded — that's a sender-side capacity issue, not a recipient signal.

## Live preview

As you adjust knobs, the **Live preview** panel re-fires within ~300ms and shows:

- **Current list size** — how many addresses are on the list right now under your active rules
- **With these rules** — how many would be on the list with the candidate rules, with a `+added, −removed` delta
- **Breakdown** — by-reason counts for the candidate list
- **Show sample additions** — up to 10 specific addresses that would be added, with their event counts, so you can sanity-check that the rule change catches the right kind of failures

The preview is read-only — nothing is saved until you click **Save rules**. If a preview call fails (the panel will say "Computing…" indefinitely), the saved rules are unaffected.

## Reason priority

An address often matches multiple rules. The wire `reason` field on the Undeliverable list (and the `/v1/undeliverable` API response) is the highest-priority match, in this order:

1. `permanent_bounce`
2. `complaint`
3. `rejected`
4. `repeated_transient`
5. `undetermined`
6. `soft_bounce_accumulation`

So if an address has both a permanent bounce and 5 repeated transient bounces, it appears with `reason: permanent_bounce` — not both.

## Saving and the audit trail

**Save rules** persists the rule body and stamps a short version hash. Every change is captured in the [Audit Log](/team/audit-log) with before/after snapshots of the rule and the operator who made the change.


Each saved rule set carries a version identifier, which is also exposed to the API so programmatic consumers can tell when your rules have changed and re-sync accordingly. See the developer API reference for details.


## Removing an address from the list

Changing rules controls **which** addresses are detected. To remove a specific address (without changing the rules for everyone), use the **Allow** action on the [Undeliverable List](/reports/undeliverable-list#allowing-delivery-to-an-address). Allowed addresses are recorded as exclusions and override the rule outcome until a new failure event comes in.

## Permissions

| Action | Required permission |
|--------|---------------------|
| View the Classification Rules page | `undeliverable.view` |
| Save changes | `undeliverable.configure` |

By default only **Owner** and **Org Admin** roles can change rules — changing classification policy affects every API caller, every team member's view of the list, and every notification rule that's keyed off undeliverable counts. Other roles see the page in view-only mode with a banner.

The **Allow / Re-list** actions on the Undeliverable list itself use a separate permission (`undeliverable.manage`), so a member-level operator can clear individual addresses without being trusted to change the org-wide rule set.

## What's next?

- See [Undeliverable List](/reports/undeliverable-list) for the day-to-day workflow of triaging individual addresses.
- The [Deliverability Reports](/reports/deliverability-reports) show aggregate bounce and complaint rates — useful for picking rule thresholds based on real volumes.
- For programmatic access to the rules (read-only), see `GET /v1/undeliverable/rules` in the API reference.