> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ruber.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Filters, blocks & forwarding

> What happens to mail as it arrives: rules that file it, senders you refuse, and forwarding it somewhere else.

**Required permission:** Filters → Read/Write for rules and blocks; Forwarding →
Read/Write for forwarding and the auto-reply.

<Warning>
  **Forwarding is its own permission because it sends.**

  A forward relays every message that arrives, and an auto-reply answers
  strangers. Both put mail on the wire under your domain's reputation, and neither
  is covered by Messages or Sending — so it is a separate box to tick.
</Warning>

## Filters

```
GET    /v1/filters        POST   /v1/filters
GET    /v1/filters/{id}   PATCH  /v1/filters/{id}   DELETE /v1/filters/{id}
```

```bash theme={null}
curl -X POST https://app.ruber.me/api/v1/filters \
  -H "Authorization: Bearer $RUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Invoices",
    "field": "subject",
    "op": "contains",
    "value": "invoice",
    "action": "label",
    "argument": "Billing"
  }'
```

| Field      |              |                                                                       |
| ---------- | ------------ | --------------------------------------------------------------------- |
| `name`     | **required** | Up to 64 characters.                                                  |
| `field`    | **required** | `from`, `to` or `subject`.                                            |
| `op`       | **required** | `contains` or `is`.                                                   |
| `value`    | **required** | What to match, up to 120 characters.                                  |
| `action`   | **required** | `move`, `label`, `star` or `read`.                                    |
| `argument` |              | The folder for `move`, the label for `label`. Nothing else takes one. |
| `position` |              | Where in the run order. Defaults to the end.                          |
| `enabled`  |              | `false` keeps the rule without running it.                            |

### Order is the whole point

Filters run top to bottom by `position`, and the list always comes back in that
order. A rule that files everything from a domain into Archive, sitting above a
rule that stars invoices from that domain, means **the invoices are never
starred**.

A new rule goes to the end unless you say otherwise. Appending cannot change
what existing rules do; prepending silently can.

<Note>
  **`argument` is required by exactly two actions and refused by the other two.**

  `move` needs a folder and `label` needs a label. `star` and `read` act on the
  message itself and take nothing — sending one is refused rather than ignored,
  because a silently dropped argument looks like a rule that works and does the
  wrong thing.

  The same check runs on `PATCH`, against the **result** rather than the change.
  Switching a `move` filter to `star` without clearing its argument is the obvious
  mistake, and it is caught with a sentence rather than a constraint name.
</Note>

Deleting a rule leaves a gap in the numbering. That is deliberate: order is
decided by comparison, not by the numbers being consecutive, and renumbering
would rewrite rules you did not touch.

## Blocked senders

```
GET    /v1/blocked-senders
POST   /v1/blocked-senders
DELETE /v1/blocked-senders/{id}
```

```bash theme={null}
curl -X POST https://app.ruber.me/api/v1/blocked-senders \
  -H "Authorization: Bearer $RUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pattern": "@spam-domain.example"}'
```

A block is either **a whole address** (`nuisance@example.com`) or **a domain
with a leading `@`** (`@example.com`). Anything else is refused.

Patterns are stored lowercased, which is what makes them match — an address
pasted out of a signature is routinely mixed case, and a block that silently
failed because somebody typed a capital is worse than no block at all. The
response reports the stored form.

`DELETE` accepts **the pattern as well as the id**, since the pattern is what
you have in hand. Blocking something already blocked succeeds and changes
nothing: you wanted them refused, and they are.

There is no `PATCH`. Editing a block into a different one is deleting it and
making another, and a half-applied edit would leave a sender neither blocked nor
allowed for as long as it took to notice.

## Forwarding and auto-reply

```
GET   /v1/forwarding                    — every mailbox
GET   /v1/forwarding?mailbox=you@…      — one
PATCH /v1/forwarding                    — change one
```

```json theme={null}
{
  "data": [
    {
      "mailbox": "you@yourdomain.com",
      "forward": { "enabled": true, "to": "relay@example.com", "since": "2026-09-09T17:52:00.000Z" },
      "reply": { "enabled": false, "subject": "Out of office", "body": "Away until Monday.", "since": null },
      "updated_at": "2026-09-09T17:52:00.000Z"
    }
  ]
}
```

**Every mailbox is listed, including ones never configured.** Returning only the
configured ones would make "forwarding is off" indistinguishable from "that
mailbox does not exist".

```bash theme={null}
curl -X PATCH https://app.ruber.me/api/v1/forwarding \
  -H "Authorization: Bearer $RUBER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mailbox": "you@yourdomain.com",
    "forward_to": "relay@example.com",
    "forward_enabled": true
  }'
```

| Field                         |                                            |
| ----------------------------- | ------------------------------------------ |
| `mailbox`                     | **required.** Which mailbox this is about. |
| `forward_to`                  | Where to relay. `null` clears it.          |
| `forward_enabled`             | Needs `forward_to` set first.              |
| `reply_subject`, `reply_body` | The automatic answer.                      |
| `reply_enabled`               | Needs a non-empty `reply_body` first.      |

<Note>
  **Set the destination before turning it on.** Enabling forwarding with nowhere
  to forward to, or an auto-reply with nothing to say, is refused rather than
  stored as a setting that does nothing. Both can be done in one call.

  **`since` is re-stamped every time you switch one on.** It is what stops a
  backlog going out the moment forwarding starts — only mail arriving after it is
  relayed. Keeping an older stamp would mean enabling forwarding today relayed
  everything received since the first time it was ever enabled.
</Note>

<Warning>
  **A Private mailbox cannot be forwarded.** The server holds no key for it, so
  there is nothing to relay but ciphertext the recipient could not open. Refused,
  not silently ignored.
</Warning>

## Organization rules, not personal ones

Like everything else a key touches, these are the organization's. Filters and
blocks a person makes in the web app belong to that person and are invisible
here; ones a key creates are visible to your team in the dashboard.

## Errors

| Code              | HTTP  | Cause                                                                                                                                                                                                                                                       |
| ----------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_request` | `400` | A field outside its vocabulary, an `argument` on the wrong action or missing from the right one, a pattern that is neither an address nor a domain, enabling forwarding with no destination or an auto-reply with no body, or forwarding a Private mailbox. |
| `forbidden`       | `403` | The key lacks the scope.                                                                                                                                                                                                                                    |
| `not_found`       | `404` | No organization filter, block or mailbox with that id, pattern or address.                                                                                                                                                                                  |

See [Errors](/api/introduction#errors) for the full response shape.
