Перейти к документации
CLI

Контакты, аудитории и рассылки

Каждая команда для адресной книги, аудиторий, рассылок и списка подавления, с разобранными примерами.

Как они связаны

Четыре пространства имён охватывают людей, которым вы пишете. Контакты это адресная книга рабочего пространства, аудитории это именованные списки контактов, рассылка отправляет одно письмо всем в нескольких аудиториях, а список подавления хранит адреса, на которые рабочее пространство не отправляет. Каждая команда вызывает один метод SDK, поэтому страницы SDK описывают те же вызовы подробнее.

  • У контакта нет идентификатора. Ключом, который принимает каждая команда contacts, служит его адрес, без пробелов по краям и в нижнем регистре, поэтому [email protected] и [email protected] это один контакт. У аудитории идентификатор aud_, у рассылки brd_, а у записи о подавлении тот идентификатор, который выводит suppressions list.
  • Каждый контакт входит в аудиторию по умолчанию, пока он существует. Эту аудиторию нельзя удалить, очистить или проредить, и её builtin равен default.
  • Адресная книга принадлежит рабочему пространству, поэтому каждый участник и каждый ключ читают и пишут одну и ту же.
  • Каждое пространство имён откликается и на форму единственного числа, как в openemail contact get, и работают обычные псевдонимы: ls, show, new, edit и rm. В suppressions, где глаголы называются add и remove, new ведёт к add, а rm к remove.

openemail <namespace> <verb> --help показывает каждый флаг с типом, scope, эндпоинт и то, что возвращает команда. Добавьте --json, чтобы получить ту же страницу как данные.

Контакты

Адресная книга рабочего пространства: люди, которым участник писал из редактора приложения, плюс все, кого сохранили вручную. Приходящая почта никого не добавляет, как и отправка через API или CLI.

КомандаЧто делает
openemail contacts listОдна страница сохранённых контактов, сначала те, с кем переписывались недавно. --source оставляет контакты manual или auto, а --q ищет по именам и адресам
openemail contacts get <email>Один контакт со всеми аудиториями, в которые он входит
openemail contacts create --email <value>Сохранить новый контакт с --name, --notes и --audience-ids. Адрес, который уже есть в книге, отклоняется с 409 contact_exists
openemail contacts update <email>Изменить --name или --notes, где null очищает значение. Сам адрес изменить нельзя
openemail contacts delete <email>Удалить контакт вместе с заметками, фото и членством и скрыть адрес, чтобы редактор не записал его снова
openemail contacts set-audiences <email> --audience-ids <a,b>Сделать так, чтобы контакт входил ровно в эти аудитории. Аудитория по умолчанию всегда сохраняется
openemail contacts list-peopleВсе со страницы «Контакты»: сохранённые контакты и, с threads:read, каждый адрес, замеченный в почте, с числом цепочек. --sort, --q, --email и --blocked сужают список
openemail contacts save <email>Сохранить адрес, оставить адрес, записанный при отправке, или вернуть удалённый. Никогда не ошибка, в каком бы состоянии ни был адрес
openemail contacts delete-many <emails...>Удалить и скрыть от 1 до 200 адресов за один вызов
openemail contacts set-photo <email> <data>Загрузить фото из файла или из stdin через -: PNG, JPEG, WebP или GIF до 5 МБ
openemail contacts remove-photo <email>Убрать фото и удалить сохранённое изображение
openemail contacts block <email>Внести адрес в список блокировки рабочего пространства, чтобы почта с него отклонялась. Плюс-тег отбрасывается
openemail contacts unblock <email>Снять каждое правило списка блокировки, которое блокирует адрес, включая правило на весь домен
openemail contacts list-threads <email>Цепочки, которые адрес писал или в которых писали ему, во всех папках. --q ищет внутри них
openemail contacts activity <email>Почта, полученная с адреса и отправленная на него за период, 90 дней, если --minutes не говорит иначе, с цепочками, ждущими ответа, и медианным временем ответа в каждую сторону

Аудитории

Именованные списки контактов, до 100 в рабочем пространстве. Прежде чем адрес попадёт в аудиторию, он должен быть контактом, кроме как через import-contacts, который сохраняет новые адреса по ходу дела.

КомандаЧто делает
openemail audiences listОдна страница аудиторий, сначала аудитория по умолчанию, остальные новые сверху, каждая с contactCount
openemail audiences growthКак росли аудитории за период, 30 дней, если --days или --minutes не говорит иначе: вступления и отписки по интервалам и итоги
openemail audiences get <id>Одна аудитория со свежим contactCount
openemail audiences create --name <value>Создать пустую аудиторию с необязательным --description. Имена не обязаны быть уникальными
openemail audiences update <id>Изменить --name или --description. Состав не затрагивается
openemail audiences delete <id>Удалить аудиторию, сохранив её контакты. Аудиторию по умолчанию удалить нельзя
openemail audiences empty <id>Вынуть все контакты и сохранить аудиторию с её идентификатором, именем и описанием
openemail audiences list-contacts <id>Одна страница контактов аудитории с тем, когда каждый вступил и отписался ли он. --sort, --q, --source и --statuses сужают её
openemail audiences add-contact <id> --email <value>Добавить в аудиторию один существующий контакт. Добавление того, кто уже там есть, ничего не меняет
openemail audiences remove-contact <id> <email>Вынуть один контакт. Контакт, которого нет в аудитории, даёт 404
openemail audiences add-contacts <id> --emails <a,b>Добавить до 200 существующих контактов и сообщить в missing адреса, которые не являются контактами
openemail audiences remove-contacts <id> --emails <a,b>Вынуть до 200 контактов и сообщить о тех, которых в ней не было
openemail audiences import-contacts <id> --contacts <json|@file|->Импортировать до 500 строк { email, name }, сохраняя адреса, которые ещё не являются контактами

Рассылки

Одно письмо всем в не более чем 10 аудиториях, отправленное отдельной копией каждому человеку, с заполненными полями подстановки и ссылкой для отписки. Каждая копия это обычное письмо со своим идентификатором msg_, событиями и вебхуками.

КомандаЧто делает
openemail broadcasts preview --audience-ids <a,b>Посчитать, до кого дошла бы рассылка этим аудиториям и кого она пропустила бы как отписавшихся или подавленных. Ничего не отправляет
openemail broadcasts send --audience-ids <a,b> --from <value>Отправить с --subject и --html или --text либо с сохранённым --template, сейчас или в --scheduled-at
openemail broadcasts listОдна страница рассылок, новые сверху, с живыми счётчиками. --audience-id оставляет те, что отправлены этой аудитории
openemail broadcasts get <id>Одна рассылка со статусом и живыми счётчиками: эту команду опрашивают, пока идёт отправка
openemail broadcasts stats <id>Итоги по доставке, отказам, открытиям, кликам и отпискам и ряд по интервалам --grain, по часу, если не указано иное
openemail broadcasts list-recipients <id>Кому ушла каждая копия и что с ней стало. --filter оставляет одну группу, например bounced или not_opened
openemail broadcasts get-recipient <id> <email-id>Копия одного человека, с темой, HTML и текстом ровно в том виде, в каком он их получил
openemail broadcasts cancel <id>Остановить рассылку, которая запланирована, стоит в очереди или ещё отправляется. Ушедшие копии отозвать нельзя

Подавления

Адреса, на которые это рабочее пространство не отправляет: жёсткие отказы и жалобы, записанные по мере появления, и любой адрес, который вы добавили вручную. Отправка на такой адрес отклоняется для этого получателя до того, как что-то уйдёт.

КомандаЧто делает
openemail suppressions listОдна страница списка, новые сверху. --reason оставляет bounce, complaint или manual, а --q ищет
openemail suppressions get <id>Одна строка: адрес, причина, подробности, которые нёс отказ или жалоба, и можно ли её удалить
openemail suppressions add --email <value>Прекратить отправку на адрес. Добавление адреса, который уже есть, возвращает его строку
openemail suppressions remove <id>Снова разрешить почту на адрес. Жёсткий отказ удалить нельзя

Список подавления и список блокировки это разные списки. suppressions add останавливает почту, уходящую на адрес, а contacts block отклоняет почту, приходящую с него.

Scope

Большинству команд нужен scope чтения или записи их пространства имён. Нескольким нужен другой, потому что они читают или меняют что-то ещё:

ScopeКоманды
contacts:readcontacts list, get и list-people
contacts:writecontacts create, update, delete, save, delete-many, set-photo и remove-photo, а также audiences import-contacts вместе с audiences:write
audiences:readaudiences list, growth, get и list-contacts, а также broadcasts preview, так что ключ, который не может отправлять, всё равно может показать число
audiences:writeВсе остальные команды audiences и contacts set-audiences. contacts create --audience-ids нужен он вместе с contacts:write
threads:readcontacts list-threads и activity, а также адреса, замеченные в почте, в list-people
settings:readsuppressions list и get
settings:writesuppressions add и remove, а также contacts block и unblock
emails:readbroadcasts list, get, stats, list-recipients и get-recipient
emails:sendbroadcasts send, которому нужен ещё и audiences:read, и broadcasts cancel
  • Ключ, ограниченный определёнными адресами или доменами, читает и пишет ту же адресную книгу, что и любой другой ключ. Он видит только рассылки, отправленные с адреса или домена, который ему выдан, получает из list-people одни сохранённые контакты и получает отказ 422 capability_unsupported от contacts list-threads, activity, block и unblock, а также от suppressions add и remove.
  • Вход через браузер участника, у которого есть доступ только к некоторым адресам, получает отказ 422 capability_unsupported в каждой команде contacts, audiences и broadcasts. suppressions add отклоняет вход через браузер любого, кроме владельца рабочего пространства.

Разобранные примеры

Соберите аудиторию из файла, а затем посчитайте, до кого дошла бы рассылка ей. import-contacts сохраняет адреса, которые ещё не контакты, и повторный запуск ничего не создаёт и не добавляет дважды.

contacts.json
[  { "email": "[email protected]", "name": "Ada Lovelace" },  { "email": "[email protected]", "name": "Grace Hopper" },  { "email": "[email protected]" }]
Собрать аудиторию и посчитать её
AUDIENCE=$(openemail audiences create --name 'Product updates' --json | jq -r .id)openemail audiences import-contacts "$AUDIENCE" --contacts @contacts.jsonopenemail broadcasts preview --audience-ids "$AUDIENCE"

Проверьте рассылку с --dry-run, который выводит запрос и ничего не отправляет, а затем отправьте её. Рассылка создаётся сразу и отправляется в фоне, поэтому опрашивайте get, чтобы следить за ней. В этом теле нет {{unsubscribeUrl}}, поэтому каждая копия получает однострочный футер для отписки.

broadcast.json
{  "audienceIds": ["aud_4c1b8e2a7d9f05c36b4e8a71"],  "from": "Acme <[email protected]>",  "subject": "{{firstName|Hello}}, the September release is out",  "html": "<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>",  "scheduledAt": "2026-10-01T09:00:00Z"}
Проверить рассылку и отправить её
openemail broadcasts send --data @broadcast.json --dry-runBROADCAST=$(openemail broadcasts send --data @broadcast.json --yes --json | jq -r .id)openemail broadcasts get "$BROADCAST"openemail broadcasts stats "$BROADCAST" --grain day

Посмотрите, до кого рассылка не дошла. --ndjson выводит по одному получателю в строке, а --all --json один документ со всеми страницами.

До кого не дошло
openemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter bounced --ndjson | jq -r .emailopenemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter not_opened --all --json | jq ".items | length"openemail suppressions list --reason bounce --all --max 50

Скопируйте подписанных участников одной аудитории в другую. jq превращает поток в тело, которое принимает add-contacts, а --data - читает его из stdin. --max 200 ограничивает его 200 адресами, которые принимает один вызов.

Копирование подписанных участников
openemail audiences list-contacts aud_9f2c4b7e1a0d63d84c5f2e7b --statuses subscribed --max 200 --ndjson \  | jq -s '{ emails: map(.email) }' \  | openemail audiences add-contacts aud_1c4e7a9b2d0f36e85a7c1b4d --data -

Удалите все контакты одного домена, записанные редактором. delete-many принимает до 200 адресов за вызов, поэтому xargs -n 200 делит более длинный список. Сначала проверьте пакеты с --dry-run, потому что отмены нет.

Удаление по домену
openemail contacts list --source auto --all --ndjson \  | jq -r 'select(.email | endswith("@old-vendor.example")) | .email' > leaving.txtxargs -n 200 openemail contacts delete-many --dry-run < leaving.txtxargs -n 200 openemail contacts delete-many --yes < leaving.txt

Прекратите отправку на адрес, снова разрешите другой и заблокируйте отправителя. removable говорит, какие строки примет suppressions remove.

Подавить, разрешить и заблокировать
openemail suppressions add --email [email protected]openemail suppressions list --q [email protected] --json | jq -r '.items[] | select(.removable) | .id'openemail suppressions remove 7b1e2c3d-4f5a-4b6c-8d7e-9f0a1b2c3d4e --yesopenemail contacts block [email protected]

Подтверждения и коды подтверждения

Эти команды просят подтверждения в терминале перед запуском:

Пространство имёнПросит подтверждения
contactsdelete, delete-many, remove-photo и unblock
audiencesdelete, empty, remove-contact и remove-contacts
broadcastssend и cancel
suppressionsremove
  • --yes подтверждает за вас. Без присмотра, с --json или --no-input, в CI или без терминала, команда, которая спросила бы, останавливается с Refusing to run unattended. Pass --yes to confirm. и кодом выхода 2.
  • --dry-run выводит запрос, который отправила бы команда, и завершается с кодом 0, ничего не спрашивая и ничего не меняя.
  • При входе через браузер audiences delete сначала спрашивает код подтверждения, как веб-приложение. --yes никогда его не пропускает, а без присмотра команда останавливается с кодом выхода 4. Заранее запустите openemail verify или используйте API-ключ, у которого код не спрашивают никогда.
  • audiences empty никогда не спрашивает код подтверждения, поэтому проверьте идентификатор, прежде чем передавать --yes.

Постраничный вывод

Каждая команда, которая выводит список, читает одну страницу. Если осталось ещё, передайте выведенный курсор в --cursor с теми же фильтрами или прочитайте всё:

  • --all читает все страницы и передаёт элементы потоком: таблицей в терминале и по одному JSON-объекту в строке при передаче в конвейер или с --ndjson.
  • --max <n> останавливается после стольких элементов и подразумевает --all.
  • --json выводит один документ { items, hasMore, nextCursor }, в том числе с --all.
  • Неверный или устаревший курсор даёт 400 invalid_cursor. Начните заново без него.
КомандаРазмер страницы
openemail contacts listОт 1 до 200, 50, если --limit не говорит иначе
openemail contacts list-peopleОт 1 до 100, 25, если --limit не говорит иначе
openemail contacts list-threadsОт 1 до 100, 25, если --limit не говорит иначе
openemail audiences listОт 1 до 100, 25, если --limit не говорит иначе
openemail audiences list-contactsОт 1 до 200, 50, если --limit не говорит иначе
openemail broadcasts listОт 1 до 100, 25, если --limit не говорит иначе
openemail broadcasts list-recipientsОт 1 до 200, 50, если --limit не говорит иначе
openemail suppressions listОт 1 до 100, 25, если --limit не говорит иначе

Полезно знать

  • contacts create отклоняет адрес, который уже есть в книге, с 409 contact_exists, поэтому повтор никогда не перезапишет имя, которое кто-то исправил. contacts save никогда не отказывает: он сохраняет, оставляет или возвращает адрес, в каком бы состоянии тот ни был.
  • contacts delete принимает и адрес, который встречался только в почте, и это убирает человека из list-people. Почта остаётся. Отмены нет: если снова сохранить адрес, контакт начнётся без имени, без заметок и без аудиторий, кроме аудитории по умолчанию.
  • Адрес это сама суть контакта, поэтому contacts update не может его изменить. Перенос контакта это delete и create.
  • contacts set-photo читает изображение из файла или из stdin через -. Передайте --content-type, например image/jpeg: без него изображение может уйти как application/octet-stream, и сервер отклонит его с 422 invalid_image.
  • broadcasts send --scheduled-at принимает время ISO 8601, например 2026-10-01T09:00:00Z, или длительность ISO 8601, например PT2H или P1D, до 365 дней вперёд. Короткие задержки, которые принимает send --at, например 2h, здесь отклоняются.
  • Поля подстановки работают в --subject, --html и --text: {{firstName}}, {{lastName}}, {{name}}, {{email}} и {{unsubscribeUrl}}, у каждого может быть запасное значение после черты, как в {{firstName|there}}. Тело без {{unsubscribeUrl}} получает однострочный футер для отписки. Шаблон отправляется как есть, поэтому ставьте ссылку в шаблон.
  • Рассылка сверяется с месячным лимитом отправок тарифа до того, как что-либо будет записано, и каждая копия считается одной отправкой. Рассылка, которую лимит не покрывает, отклоняется с 429 send_quota_exceeded, и после неё ничего не остаётся.
  • Передавайте свой --idempotency-key в broadcasts send, если скрипт может повторить этот шаг. С тем же ключом в ответ приходит уже созданная рассылка, а новая не отправляется.
  • Контакт, отписавшийся от рассылки, остаётся в аудитории с заполненным unsubscribedAt, и следующие рассылки этой аудитории его пропускают. audiences list-contacts --statuses unsubscribed перечисляет таких.
  • Жёсткий отказ остаётся в списке подавления. suppressions remove отклоняет его с 409 suppression_not_removable, а removable в каждой строке сообщает об этом заранее.

Ваши входящие,
на ваших условиях.

Почтовая инфраструктура для бизнеса, ИИ, агентов и личной почты. Создана для масштаба, приватности и контроля. Всё, что должно было быть в почте с первого дня.

OpenEmail

Почтовая инфраструктура для бизнеса, ИИ, агентов и личной почты. Создана для масштаба, приватности и контроля. Всё, что должно было быть в почте с первого дня.

© 2026 OpenEmail. Все права защищены.