---
title: "Rules"
description: "What happens to mail as it arrives."
url: "https://nextmail.sh/docs/mcp/tools/rules"
area: "MCP server"
category: "Tools"
---

# Rules

What happens to mail as it arrives.

## Rules tools

| Tool | What it does |
| --- | --- |
| listRules | Every rule on the active connection, in the order they are evaluated, a page at a time, with what each one does and how often it has fired. |
| getRule | One rule in full: its conditions, its actions and whether it is on. |
| createRule | Write a rule: conditions over an arriving message, and what should happen to anything matching them. The rule is created DISABLED. |
| testRule | Which of the last thirty days’ messages a rule would have caught, and what it would have done to them. Changes nothing. |
| setRuleEnabled | Turn one rule on or off, once a person has read it back. |
| updateRule | Change a rule: its name, conditions, actions, whether it stops the rules below, whether it is on, or its position. |
| deleteRule | Delete a rule for good. Nothing it already did is undone. A chat always asks first. |
| reorderRules | Set the order the rules run in, naming every rule you can see once. |
| listRuleRuns | What the rules did, newest first: which rule matched which message, what it did and what failed. Returned a page at a time. |

> `createRule` writes the rule DISABLED, which is the one place this server deliberately differs from the REST API. `POST /rules` defaults to enabled. A rule that archives, trashes or forwards mail should not start doing it on the strength of a chat message: write it, call `testRule` to show the person you are working for which of their own messages it would have caught, and only then ask for `setRuleEnabled`.

> `updateRule`, `deleteRule` and `reorderRules` change the rules that exist, exactly as `PATCH /rules/{id}`, `DELETE /rules/{id}` and `POST /rules/reorder` do. A deleted rule cannot be restored and a reorder changes what every later message does, so `updateRule` and `deleteRule` always show the person a card to approve in the assistant, and a client should ask first as well. `listRuleRuns` reads what the rules did.

> Rules belong to the CONNECTION, so these act on whichever mailbox `setActiveConnection` last named, and a rule a colleague wrote is one of them. A mailbox holds 100 rules, each with at most 20 conditions and 10 actions.

> Nothing here is retroactive. A rule decides what happens to mail arriving after it is enabled; it does not sweep a mailbox that already exists, and `testRule` reports rather than files.

> Some tools on this server make a change the REST API guards with a verification code, and ask for the same code. Until the client has verified a code in the last 60 minutes, or the person has chosen Allow changes for 60 minutes on it in Account → Connected apps, such a tool answers with a result that starts `Refused (step_up_required):` and changes nothing. `emptyAudience` never asks for a code. The API Authentication page lists every tool that asks, and shows how to ask for a code and verify it.

## Reference

### `listRules`

Mail rules on the active connection, in the order they run. A rule is a set of conditions over an inbound message and a list of things to do to anything matching them: label it, archive it, forward it. Order matters: rules run top to bottom and one marked "stops here" prevents every rule below it from running. Reports whether each is enabled, which is the fact worth reading. A disabled rule is doing nothing at all. Use getRule for one in full, including its conditions and its actions. One page at a time: when more follow, the last line gives a cursor to pass back, with the same filter, for the next page.

- Scopes: `rules:read`.
- The app's assistant runs it without asking.
- Toolkit: `rules`.

**Inputs**

- `enabled` (`boolean`)
- `limit` (`integer`, at least 1, at most 100, default `50`)
- `cursor` (`string`)

Also available in: API [`GET /rules`](https://nextmail.sh/docs/api/reference/rules#get-rules); TypeScript [`nextmail.rules.list()`](https://nextmail.sh/docs/sdk/reference/rules#list), [`nextmail.rules.listAll()`](https://nextmail.sh/docs/sdk/reference/rules#listAll), [`nextmail.rules.iterate()`](https://nextmail.sh/docs/sdk/reference/rules#iterate); Python [`rules.list()`](https://nextmail.sh/docs/python/reference/rules#list), [`rules.list_all()`](https://nextmail.sh/docs/python/reference/rules#listAll), [`rules.iterate()`](https://nextmail.sh/docs/python/reference/rules#iterate); Ruby [`rules.list`](https://nextmail.sh/docs/ruby/reference/rules#list), [`rules.list_all`](https://nextmail.sh/docs/ruby/reference/rules#listAll), [`rules.iterate`](https://nextmail.sh/docs/ruby/reference/rules#iterate); PHP [`rules->list`](https://nextmail.sh/docs/php/reference/rules#list), [`rules->listAll`](https://nextmail.sh/docs/php/reference/rules#listAll), [`rules->iterate`](https://nextmail.sh/docs/php/reference/rules#iterate); Go [`Rules.List`](https://nextmail.sh/docs/go/reference/rules#list), [`Rules.ListAll`](https://nextmail.sh/docs/go/reference/rules#listAll), [`Rules.Iterate`](https://nextmail.sh/docs/go/reference/rules#iterate); Java [`rules().list`](https://nextmail.sh/docs/java/reference/rules#list), [`rules().listAll`](https://nextmail.sh/docs/java/reference/rules#listAll), [`rules().iterate`](https://nextmail.sh/docs/java/reference/rules#iterate); C# [`Rules.ListAsync`](https://nextmail.sh/docs/csharp/reference/rules#list), [`Rules.ListAllAsync`](https://nextmail.sh/docs/csharp/reference/rules#listAll), [`Rules.IterateAsync`](https://nextmail.sh/docs/csharp/reference/rules#iterate).

### `getRule`

One rule in full, by id (rul_…): every condition it tests, every action it takes, whether it stops the rules below it, and how many messages it has matched. Read this back to the person before asking for a rule to be enabled. The conditions are the part that decides what happens to their mail, and a rule reads very differently from the sentence that asked for it.

- Scopes: `rules:read`.
- The app's assistant runs it without asking.
- Toolkit: `rules`.

**Inputs**

- `id` (`string`, required)

Also available in: API [`GET /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#get-rules-id); TypeScript [`nextmail.rules.get()`](https://nextmail.sh/docs/sdk/reference/rules#get); Python [`rules.get()`](https://nextmail.sh/docs/python/reference/rules#get); Ruby [`rules.get`](https://nextmail.sh/docs/ruby/reference/rules#get); PHP [`rules->get`](https://nextmail.sh/docs/php/reference/rules#get); Go [`Rules.Get`](https://nextmail.sh/docs/go/reference/rules#get); Java [`rules().get`](https://nextmail.sh/docs/java/reference/rules#get); C# [`Rules.GetAsync`](https://nextmail.sh/docs/csharp/reference/rules#get).

### `createRule`

Create a mail rule on the active connection: conditions over an inbound message, and what should happen to anything matching them. THE RULE IS CREATED DISABLED. It does nothing to any mail until a person turns it on, because a rule that archives or forwards should not start doing that on the strength of a chat message. Call testRule next to show which of the last thirty days’ messages it would have caught, read the rule back, and only then ask whether to enable it with setRuleEnabled. Rules run in order and a new one goes last: reorderRules changes the order, updateRule edits a rule and deleteRule removes it.

- Scopes: `rules:write`.
- The app's assistant always asks first.
- Asks for a verification code, the same as [`POST /rules`](https://nextmail.sh/docs/api/reference/rules#post-rules).
- Toolkit: `rules`.

**Inputs**

- `name` (`string`, required, 1 to 100 characters)
- `description` (`string`, up to 500 characters): A note on what the rule is for, shown under its name in the app.
- `match` (`string`, one of `"all"`, `"any"`, default `"all"`)
- `conditions` (`object[]`, required)
  - `field` (`string`, required, one of `"from"`, `"from_domain"`, `"envelope_from"`, `"to"`, `"cc"`, `"bcc"`, `"recipient"`, `"reply_to"`, `"delivered_to"`, `"subject"`, `"body"`, `"header"`, `"list_id"`, `"attachment_name"`, `"attachment_type"`, `"has_attachment"`, `"attachment_size"`, `"message_size"`, `"spam"`, `"bounced"`, `"hour"`, `"weekday"`)
  - `op` (`string`, required, one of `"matches"`, `"contains"`, `"equals"`, `"starts_with"`, `"ends_with"`, `"gt"`, `"lt"`)
  - `value` (`string`, required)
  - `header` (`string`)
  - `negate` (`boolean`, default `false`)
- `actions` (`object[]`, required)
  - `type` (`string`, required, one of `"label"`, `"remove_label"`, `"archive"`, `"mark_read"`, `"star"`, `"spam"`, `"trash"`, `"forward"`, `"reply"`, `"block_sender"`, `"reject"`)
  - `value` (`string`)
- `stopProcessing` (`boolean`, default `false`)

Also available in: API [`POST /rules`](https://nextmail.sh/docs/api/reference/rules#post-rules); TypeScript [`nextmail.rules.create()`](https://nextmail.sh/docs/sdk/reference/rules#create); Python [`rules.create()`](https://nextmail.sh/docs/python/reference/rules#create); Ruby [`rules.create`](https://nextmail.sh/docs/ruby/reference/rules#create); PHP [`rules->create`](https://nextmail.sh/docs/php/reference/rules#create); Go [`Rules.Create`](https://nextmail.sh/docs/go/reference/rules#create); Java [`rules().create`](https://nextmail.sh/docs/java/reference/rules#create); C# [`Rules.CreateAsync`](https://nextmail.sh/docs/csharp/reference/rules#create).

### `testRule`

A dry run: which of the recent messages in the inbox this rule WOULD have matched, and what it would have done to them. Changes nothing: no message is labelled, archived, forwarded or replied to, and the rule is not enabled. This is what to show a person before asking whether to turn a rule on. It scores the newest message each thread RECEIVED and never the mailbox’s own sends or replies, because a rule only ever runs on arriving mail. It reads STORED messages rather than deliveries, which costs the answer two different ways and both belong in whatever you report. Conditions on a raw header, on a mailing-list id, on the SMTP envelope, on message size or on the delivered-to address cannot be answered at all and are reported as untestable rather than counted as misses. Attachment, hour and weekday conditions ARE answered, but from stored mail rather than from the delivery. Stored mail drops images inlined into the body, which delivery counts as attachments, and keeps only the sender’s own Date: header, where delivery uses our receipt clock. Those are therefore reported as approximate, and the dates printed beside each match are the sender’s. A message that arrived encrypted has no readable body at all, so a body condition is neither matched nor missed on it. The result says how many were skipped that way, and that number belongs in whatever you report. Pass those caveats on rather than relaying the count as an exact answer.

- Scopes: `rules:read`.
- The app's assistant runs it without asking.
- Toolkit: `rules`.

**Inputs**

- `id` (`string`, required)
- `days` (`integer`, at least 1, at most 365, default `30`)
- `limit` (`integer`, at least 1, at most 200, default `50`)

Also available in: API [`POST /rules/{id}/test`](https://nextmail.sh/docs/api/reference/rules#post-rules-id-test); TypeScript [`nextmail.rules.test()`](https://nextmail.sh/docs/sdk/reference/rules#test); Python [`rules.test()`](https://nextmail.sh/docs/python/reference/rules#test); Ruby [`rules.test`](https://nextmail.sh/docs/ruby/reference/rules#test); PHP [`rules->test`](https://nextmail.sh/docs/php/reference/rules#test); Go [`Rules.Test`](https://nextmail.sh/docs/go/reference/rules#test); Java [`rules().test`](https://nextmail.sh/docs/java/reference/rules#test); C# [`Rules.TestAsync`](https://nextmail.sh/docs/csharp/reference/rules#test).

### `setRuleEnabled`

Turn a rule on or off. ENABLING A RULE STARTS IT ACTING ON REAL MAIL IMMEDIATELY: the next message that matches it is labelled, archived, forwarded or replied to without anybody being asked, and some of those cannot be undone. Only enable a rule a person has actually been shown. Call getRule to read it back and testRule to show what it would have caught, and ask. It applies to mail that arrives from now on and does not go back over messages already in the mailbox. Disabling is the reverse and is always safe: the rule stops matching and nothing it already did is undone.

- Scopes: `rules:write`.
- The app's assistant always asks first.
- Asks for a verification code, the same as [`PATCH /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#patch-rules-id).
- Toolkit: `rules`.

**Inputs**

- `id` (`string`, required)
- `enabled` (`boolean`, required)

Also available in: API [`PATCH /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#patch-rules-id); TypeScript [`nextmail.rules.update()`](https://nextmail.sh/docs/sdk/reference/rules#update); Python [`rules.update()`](https://nextmail.sh/docs/python/reference/rules#update); Ruby [`rules.update`](https://nextmail.sh/docs/ruby/reference/rules#update); PHP [`rules->update`](https://nextmail.sh/docs/php/reference/rules#update); Go [`Rules.Update`](https://nextmail.sh/docs/go/reference/rules#update); Java [`rules().update`](https://nextmail.sh/docs/java/reference/rules#update); C# [`Rules.UpdateAsync`](https://nextmail.sh/docs/csharp/reference/rules#update).

### `updateRule`

Change a rule: its name, description, conditions, actions, whether it stops the rules below it, whether it is on, or its position. What you pass replaces that part of the rule, so conditions and actions are whole lists. A rule that is on acts on the next message that matches it, so read it back with getRule and show testRule first. reorderRules sets the whole order at once.

- Scopes: `rules:write`.
- The app's assistant always asks first.
- Asks for a verification code, the same as [`PATCH /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#patch-rules-id).
- Toolkit: `rules`.

**Inputs**

- `id` (`string`, required, 1 to 128 characters): The rule, by its id (rul_…). listRules names every one.
- `name` (`string`, 1 to 100 characters)
- `description` (`string`, nullable, up to 500 characters)
- `match` (`string`, one of `"all"`, `"any"`)
- `conditions` (`object[]`)
  - `field` (`string`, required, one of `"from"`, `"from_domain"`, `"envelope_from"`, `"to"`, `"cc"`, `"bcc"`, `"recipient"`, `"reply_to"`, `"delivered_to"`, `"subject"`, `"body"`, `"header"`, `"list_id"`, `"attachment_name"`, `"attachment_type"`, `"has_attachment"`, `"attachment_size"`, `"message_size"`, `"spam"`, `"bounced"`, `"hour"`, `"weekday"`)
  - `op` (`string`, required, one of `"matches"`, `"contains"`, `"equals"`, `"starts_with"`, `"ends_with"`, `"gt"`, `"lt"`)
  - `value` (`string`, required)
  - `header` (`string`)
  - `negate` (`boolean`, default `false`)
- `actions` (`object[]`)
  - `type` (`string`, required, one of `"label"`, `"remove_label"`, `"archive"`, `"mark_read"`, `"star"`, `"spam"`, `"trash"`, `"forward"`, `"reply"`, `"block_sender"`, `"reject"`)
  - `value` (`string`)
- `stopProcessing` (`boolean`)
- `enabled` (`boolean`)
- `position` (`integer`, at least 0, at most 1000000)

Also available in: API [`PATCH /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#patch-rules-id); TypeScript [`nextmail.rules.update()`](https://nextmail.sh/docs/sdk/reference/rules#update); Python [`rules.update()`](https://nextmail.sh/docs/python/reference/rules#update); Ruby [`rules.update`](https://nextmail.sh/docs/ruby/reference/rules#update); PHP [`rules->update`](https://nextmail.sh/docs/php/reference/rules#update); Go [`Rules.Update`](https://nextmail.sh/docs/go/reference/rules#update); Java [`rules().update`](https://nextmail.sh/docs/java/reference/rules#update); C# [`Rules.UpdateAsync`](https://nextmail.sh/docs/csharp/reference/rules#update).

### `deleteRule`

Delete a rule for good. It stops acting on mail at once, and nothing it already did is undone. There is no bin for rules. setRuleEnabled with enabled false is the reversible way to stop one.

- Scopes: `rules:write`.
- The app's assistant always asks first.
- Toolkit: `rules`.

**Inputs**

- `id` (`string`, required, 1 to 128 characters): The rule, by its id (rul_…). listRules names every one.

Also available in: API [`DELETE /rules/{id}`](https://nextmail.sh/docs/api/reference/rules#delete-rules-id); TypeScript [`nextmail.rules.delete()`](https://nextmail.sh/docs/sdk/reference/rules#delete); Python [`rules.delete()`](https://nextmail.sh/docs/python/reference/rules#delete); Ruby [`rules.delete`](https://nextmail.sh/docs/ruby/reference/rules#delete); PHP [`rules->delete`](https://nextmail.sh/docs/php/reference/rules#delete); Go [`Rules.Delete`](https://nextmail.sh/docs/go/reference/rules#delete); Java [`rules().delete`](https://nextmail.sh/docs/java/reference/rules#delete); C# [`Rules.DeleteAsync`](https://nextmail.sh/docs/csharp/reference/rules#delete).

### `reorderRules`

Set the order rules run in, first to last. ruleIds has to name every rule listRules shows you, each once. Order is part of what rules do: one that stops the rules below it hides them from every message it matches.

- Scopes: `rules:write`.
- The app's assistant asks first unless you asked for it.
- Toolkit: `rules`.

**Inputs**

- `ruleIds` (`string[]`, required, 1 to 1000 items)

Also available in: API [`POST /rules/reorder`](https://nextmail.sh/docs/api/reference/rules#post-rules-reorder); TypeScript [`nextmail.rules.reorder()`](https://nextmail.sh/docs/sdk/reference/rules#reorder); Python [`rules.reorder()`](https://nextmail.sh/docs/python/reference/rules#reorder); Ruby [`rules.reorder`](https://nextmail.sh/docs/ruby/reference/rules#reorder); PHP [`rules->reorder`](https://nextmail.sh/docs/php/reference/rules#reorder); Go [`Rules.Reorder`](https://nextmail.sh/docs/go/reference/rules#reorder); Java [`rules().reorder`](https://nextmail.sh/docs/java/reference/rules#reorder); C# [`Rules.ReorderAsync`](https://nextmail.sh/docs/csharp/reference/rules#reorder).

### `listRuleRuns`

What the rules did, newest first: each time a rule matched a message, which actions it took and which of them failed. Narrow it to one rule with ruleId or to one conversation with threadId. One page at a time: when more follow, the last line gives a cursor to pass back, with the same filters, for the next page.

- Scopes: `rules:read`.
- The app's assistant runs it without asking.
- Toolkit: `rules`.

**Inputs**

- `ruleId` (`string`, 1 to 128 characters)
- `threadId` (`string`, 1 to 128 characters)
- `limit` (`integer`, at least 1, at most 100)
- `cursor` (`string`, 1 to 128 characters)

Also available in: API [`GET /rules/runs`](https://nextmail.sh/docs/api/reference/rules#get-rules-runs); TypeScript [`nextmail.rules.listRuns()`](https://nextmail.sh/docs/sdk/reference/rules#listRuns), [`nextmail.rules.listAllRuns()`](https://nextmail.sh/docs/sdk/reference/rules#listAllRuns), [`nextmail.rules.iterateRuns()`](https://nextmail.sh/docs/sdk/reference/rules#iterateRuns); Python [`rules.list_runs()`](https://nextmail.sh/docs/python/reference/rules#listRuns), [`rules.list_all_runs()`](https://nextmail.sh/docs/python/reference/rules#listAllRuns), [`rules.iterate_runs()`](https://nextmail.sh/docs/python/reference/rules#iterateRuns); Ruby [`rules.list_runs`](https://nextmail.sh/docs/ruby/reference/rules#listRuns), [`rules.list_all_runs`](https://nextmail.sh/docs/ruby/reference/rules#listAllRuns), [`rules.iterate_runs`](https://nextmail.sh/docs/ruby/reference/rules#iterateRuns); PHP [`rules->listRuns`](https://nextmail.sh/docs/php/reference/rules#listRuns), [`rules->listAllRuns`](https://nextmail.sh/docs/php/reference/rules#listAllRuns), [`rules->iterateRuns`](https://nextmail.sh/docs/php/reference/rules#iterateRuns); Go [`Rules.ListRuns`](https://nextmail.sh/docs/go/reference/rules#listRuns), [`Rules.ListAllRuns`](https://nextmail.sh/docs/go/reference/rules#listAllRuns), [`Rules.IterateRuns`](https://nextmail.sh/docs/go/reference/rules#iterateRuns); Java [`rules().listRuns`](https://nextmail.sh/docs/java/reference/rules#listRuns), [`rules().listAllRuns`](https://nextmail.sh/docs/java/reference/rules#listAllRuns), [`rules().iterateRuns`](https://nextmail.sh/docs/java/reference/rules#iterateRuns); C# [`Rules.ListRunsAsync`](https://nextmail.sh/docs/csharp/reference/rules#listRuns), [`Rules.ListAllRunsAsync`](https://nextmail.sh/docs/csharp/reference/rules#listAllRuns), [`Rules.IterateRunsAsync`](https://nextmail.sh/docs/csharp/reference/rules#iterateRuns).
