Создать правило
Условия с одной стороны, действия с другой. Включено, если вы не скажете иначе.
Выполняет настоящий запрос в вашем рабочем пространстве, с вашим собственным ключом.
POST /rules
Условия с одной стороны, действия с другой. Включено, если вы не скажете иначе.
Пример
Требует rules:write. Возвращает 201. position не принимается. Новое правило дописывается в конец списка, а перемещает его POST /rules/reorder.
curl -X POST "$OE/rules" -H "$AUTH" -H "Content-Type: application/json" \ -d '{ "name": "Receipts to their own label", "match": "all", "conditions": [ { "field": "from_domain", "op": "matches", "value": "*.stripe.com" }, { "field": "subject", "op": "contains", "value": "receipt" } ], "actions": [ { "type": "label", "value": "USER_RECEIPTS" }, { "type": "archive" } ], "stopProcessing": true }'{ "object": "rule", "id": "rul_7f3a1c94e05d3862c1f0a44b", "name": "Receipts to their own label", "description": null, "enabled": true, "position": 3, "match": "all", "conditions": [ { "field": "from_domain", "op": "matches", "value": "*.stripe.com", "negate": false }, { "field": "subject", "op": "contains", "value": "receipt", "negate": false } ], "actions": [ { "type": "label", "value": "USER_RECEIPTS" }, { "type": "archive" } ], "stopProcessing": true, "lastMatchedAt": null, "matchCount": 0, "createdAt": "2026-08-30T10:41:02.000Z", "updatedAt": "2026-08-30T10:41:02.000Z"}Созданное здесь правило ВКЛЮЧЕНО и начинает действовать со следующего сообщения. Это правильное поведение по умолчанию для вызова, сделанного человеком осознанно, и оно противоположно инструменту MCP createRule, который пишет то же самое правило ОТКЛЮЧЁННЫМ, потому что модель, решившая архивировать почту, не должна архивировать её до того, как человек прочитает правило.
Дублирующееся name в том же подключении — это rule_name_taken, 409. По именам правило узнают в журнале запусков и на экране настроек, так что два правила с именем «Newsletters» — это отчёт, который никто не сможет прочитать.
101-е правило — это rule_limit_reached, 422. Потолок защищает от скрипта в цикле, а не является учётной границей, и он не блокируется. Два создания, идущие наперегонки при 99, могут оба пройти.
О чём может спросить условие
Условие — это { field, op, value }, с необязательным header, называющим, какой заголовок читать, и необязательным negate. value на проводе ВСЕГДА строка. Числовые поля сравниваются как числа после Number(value), а два булевых поля принимают буквальные строки "true" и "false", потому что одно поле с одним типом — это схема, которую генератор OpenAPI может описать, а объединение из трёх — нет.
| Поле | Что читает | Операторы |
|---|---|---|
| `from` | Заголовок From:, нормализованный так же, как его нормализует чёрный список. | текст |
| `from_domain` | Домен из From: и его РОДИТЕЛЬСКИЕ домены, вплоть до двух меток: сообщение с mail.corp.example.com совпадёт и с corp.example.com, и с example.com, и не совпадёт ни с чем для com. | текст |
| `envelope_from` | SMTP-команда MAIL FROM. Отличается от from в любой рассылке и является единственной идентичностью, против которой можно написать reject. | текст |
| `to`, `cc`, `bcc` | Любой адрес в этом заголовке. | текст |
| `recipient` | Любой адрес в to, cc или bcc: сокращение сразу для всех трёх. | текст |
| `reply_to` | Заголовок Reply-To. | текст |
| `delivered_to` | Канонический адрес, на который была доставлена эта копия, с отброшенным плюс-тегом и приведённый к нижнему регистру, — именно так сопоставляется catch-all алиас. | текст |
| `subject` | Тема письма в том виде, в каком она пришла. | текст |
| `body` | Текстовая часть или HTML, сведённый к тексту. С ограничением, чтобы тело в 20 МБ не сканировалось целиком. | текст |
| `header` | Любой заголовок, названный в собственном поле header этого условия. Там оно обязательно и приводится к нижнему регистру перед сравнением. | текст |
| `list_id` | Заголовок List-Id: идентификатор, которым рассылка представляет себя. | текст |
| `attachment_name` | Имя файла любого вложения. | текст |
| `attachment_type` | MIME-тип любого вложения, например application/pdf. | текст |
| `has_attachment` | Есть ли вложение вообще. | equals "true" / "false" |
| `spam` | Вердикт о спаме, вынесенный на пути доставки, до запуска ваших правил. | equals "true" / "false" |
| `attachment_size` | Размер вложения в байтах. Сравнение срабатывает, когда ему удовлетворяет хотя бы одно вложение. | gt, lt, equals |
| `message_size` | Всё сообщение на проводе, в байтах. | gt, lt, equals |
| `hour` | Час получения, 0–23, UTC. | gt, lt, equals |
| `weekday` | День получения, 0–6, воскресенье — это 0, UTC. | gt, lt, equals |
| Оператор | Что он делает |
|---|---|
| `matches` | Глоб, и только глоб: * для любой последовательности символов, ? для одного. Никаких регулярных выражений. Шаблон от клиента API выполняется на пути доставки, а катастрофический бэктрекинг там — это почтовый ящик, который перестаёт принимать почту. |
| `contains` | Подстрока, без учёта регистра. |
| `equals` | Всё значение целиком, без учёта регистра. На числовом поле — числовое равенство. |
| `starts_with` | Префикс, без учёта регистра. |
| `ends_with` | Суффикс, без учёта регистра. |
| `gt`, `lt` | Числовые, только на четырёх числовых полях. Текстовое поле с gt не совпадёт никогда. |
Шаблон matches должен содержать не меньше двух собственных буквенно-цифровых символов — та же планка, что и у чёрного списка. Голая * отклоняется при записи, а не принимается, чтобы потом молча совпадать с каждым сообщением, которое когда-либо придёт: это авария, а не правило.
Условие, на которое движок не может ответить (неизвестное поле от более нового клиента, шаблон, который не компилируется, contains ""), трактуется как вопрос, который никогда не задавали, а не как «ложь», и negate его не переворачивает. Это различие несущее: отрицание сломанного условия, трактуемого как ложь, запускало бы своё правило на каждом сообщении в ящике. equals "" выполняется, потому что «тема письма пуста» — это настоящий вопрос.
Что может делать правило
| Действие | `value` | Что происходит |
|---|---|---|
| `label` | идентификатор метки | Добавляет метку. Идентификаторы USER_… берутся из GET /labels. |
| `remove_label` | идентификатор метки | Удаляет её. Указание одной и той же метки в обоих действиях разрешается до того, как сообщение будет разложено, а не отдаётся на волю того, что выполнилось последним. |
| `archive` | нет | Убирает его из папки входящих. |
| `mark_read` | нет | Снимает UNREAD. |
| `star` | нет | Добавляет STARRED. |
| `spam` | нет | Помещает его в папку «Спам». |
| `trash` | нет | Помещает его в корзину, снимая метки, которые удалённое сообщение не сохраняет. |
| `forward` | адрес | Отправляет копию дальше. Прежде чем пользоваться, прочитайте примечание ниже. |
| `reply` | идентификатор или slug шаблона | Автоматически отвечает опубликованным шаблоном, с учётом защиты от циклов ниже. |
| `block_sender` | нет | Добавляет отправителя в чёрный список, так что следующее сообщение отклоняется прямо на входе. |
| `reject` | нет | Отклоняет сообщение прямо на этапе SMTP с 550 5.7.1 Message refused by the recipient. Только по конверту. См. ниже. |
reject отклоняется при записи, если в том же правиле нет хотя бы одного условия envelope_from: reject_needs_envelope, 422. Ответ 550 адресован тому, кто передал нам сообщение, а в случае рассылки это САМА РАССЫЛКА, которая прочитает отказ как отбивающегося подписчика и отпишет читателя от всего, тогда как он хотел лишь, чтобы перестал писать один человек. Даже при написанном условии совпадение, пришедшее только из заголовочных идентичностей, понижается до помещения в «Спам», потому что конверт — единственная идентичность, на которую отказ можно честно нацелить.
forward из правила уходит через путь отправки, который ПЕРЕСОБИРАЕТ сообщение: исходная подпись DKIM не сохраняется, как и экзотические части, необычные заголовки и всё, что выходит за исходящий потолок размера, который сообщение в 25 МБ с вложениями превысит. Это копия того, что пришло, а не само пришедшее сообщение. Адрес проверяется при записи правила, поэтому неподтверждённый адрес назначения — это 422 на вызове, а не правило, которое молча теряет каждое десятое сообщение.
reply не отвечает машине. Он подавляется, когда сообщение несёт Auto-Submitted (отличный от no), Precedence: bulk|list|junk, List-Id, List-Unsubscribe, X-Autoreply или X-Autorespond, когда отправитель в конверте пуст (форма, которую принимает любой отбой) и когда заголовки вообще не удалось прочитать. Сверх того, один отправитель получает не более одного автоответа в 24 часа от данного почтового ящика. Два ящика с правилами ответа и без защиты будут писать друг другу, пока кто-нибудь не заметит.