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

Отправка и отслеживание писем

Отправляйте, отправляйте пакетами, переводите, планируйте и отменяйте почту командами `emails`, а затем следите за её доставкой, открытиями и кликами через `tracking`.

Обзор

Пространство имён emails это API отправки в виде команд, по одной на каждый метод openemail.emails в SDK. Каждая вызывает один эндпоинт и выводит то, что он возвращает. Пространство имён tracking читает открытия и клики по отправленной вами почте. openemail email работает вместо openemail emails.

Каждой команде здесь нужен вход, через браузер или по API-ключу, и один из двух scope: emails:send, чтобы отправлять, переводить, отменять и переносить, и emails:read для всего, что только читает.

Какую отправку выбрать

openemail send это написанная вручную команда со страницы «Почта», и она отправляет через emails send. Она сделана для человека за терминалом: выбирает адрес отправки, если вы не указали --from, читает тело из файла, stdin или редактора, прикрепляет файлы по пути и показывает сводку для подтверждения, прежде чем что-то уйдёт. openemail emails send принимает тело запроса флагами, по одному на поле, и ничего не спрашивает, что подходит скрипту, который точно знает, что отправляет.

sendemails send
--from <address>Обязателен, как --to, если его нет в --data. send может обойтись без него и выбрать адрес за вас
-f, --body-file <path>Флага файла для тела нет. Передайте --html "$(cat body.html)" или весь запрос в --data @email.json
-a, --attach <path>--attachments, JSON-массив файлов, каждый с filename и content в base64 или с fileId файла, который уже лежит в «Файлах»
--at <when>--scheduled-at <when>, момент в ISO 8601 или длительность, например PT1H или P2D. send принимает и короткие задержки, например 10m, 2h и 1d
--undo <seconds>--cancellable-for-seconds <n>, от 0 до 900
--translate <language>--translate '{"to":"de"}', который принимает также from, includeOriginal и subject
--template <id> --props <json>--template '{"id":"welcome","props":{"name":"Ada"}}', который может также закрепить version
--draft <id>--draft-id <id>
--thread <id>--thread-id <id>
--tag <key=value>--tags <key=value>, повторением или JSON-объектом

Только у emails send есть --tracking, чтобы отключить открытия или клики для одной отправки, --signature, --headers для своих заголовков, --attachment-delivery, чтобы выбрать между вложением файлов и ссылками на них, и --data для всего тела в виде JSON: встроенно, из файла через @path или из stdin через -.

Завершаются они по-разному. send завершается с кодом 1, когда письмо возвращается со статусом failed. emails send завершается с кодом 0 всякий раз, когда API ответил, поэтому проверяйте status в выводе.

Все команды emails

send, send-batch, translate, cancel и reschedule нужен emails:send. list, get, list-events и get-tracking нужен emails:read. Идентификатор письма это msg_ и 24 шестнадцатеричных символа, в том виде, в каком его возвращает отправка.

КомандаЧто делает
openemail emails send --from <value> --to <a,b>Отправить одно письмо сейчас, задержать его на окно отмены через --cancellable-for-seconds или запланировать через --scheduled-at. Тело это --html, --text или оба, сохранённый --template или сохранённый --draft-id
openemail emails send-batch <emails>Отправить до 100 независимых писем одним запросом из JSON-массива в файле, встроенно или из stdin через -. Каждый элемент устроен как тело emails send и проходит или не проходит сам по себе
openemail emails translate --to <value>Посмотреть заранее, что доставила бы отправка с переводом, для --subject, --html или --text. Ничего не сохраняется и не отправляется, тратится одно ИИ-действие
openemail emails listОдна страница отправленных писем, новые сверху, с отбором по --status, --from или --broadcast-id
openemail emails get <id>Одно отправленное письмо со статусом, ошибкой и временем доставки для каждого получателя и полным отчётом отслеживания, если оно отслеживалось
openemail emails list-events <id>История событий одной отправки, старые сверху: приём, планирование, отправка, доставка, отказ, жалоба, открытие, клик и остальные
openemail emails get-tracking <id>Отчёт о вовлечённости одной отправки: итоги, по одной записи на каждую отслеживаемую копию и каждая переписанная ссылка с её кликами
openemail emails cancel <id>Остановить письмо в очереди или запланированное письмо до отправки. Просит подтверждения
openemail emails reschedule <id> <scheduled-at>Перенести письмо в очереди или запланированное письмо на момент в ISO 8601 или на длительность, например PT30M, от одной секунды до 365 дней вперёд

Все команды tracking

Всем пяти нужен emails:read. tracking get, list-opens и list-clicks принимают любой из двух идентификаторов письма: msg_, который вернула его отправка, или идентификатор отслеживания tmsg_, который несут tracking list и полезные нагрузки вебхуков.

КомандаЧто делает
openemail tracking listОдна страница отслеживаемых писем, отправленных за период, новые сверху, каждое с полным отчётом. --opened и --clicked сужают её, а --no-opened оставляет те, которые никто не открыл. Период равен 30 дням, если --days или --minutes не говорит иначе
openemail tracking get-statsЦифры за панелью вовлечённости: отслеживаемые, открытые и кликнутые письма, доли открытий и кликов, временной ряд с шагом --grain, а также самые популярные ссылки, почтовые клиенты и страны
openemail tracking get <id>Отчёт о вовлечённости одного письма, тот же документ, что возвращает emails get-tracking
openemail tracking list-opens <id>Отдельные открытия, из которых складывается число открытий письма, новые сверху, каждое с пометкой human, proxy или machine. --include-machine добавляет обращения, которые не засчитаны
openemail tracking list-clicks <id>Отдельные клики по ссылкам письма, новые сверху, с исходным url каждой. --include-machine добавляет сканеры ссылок и схлопнутые повторы

tracking list и get-stats охватывают каждое отслеживаемое письмо, отправленное ящиком, включая почту, написанную в веб-приложении, и почту, отправленную MCP-инструментами или ассистентом, а emails list содержит записи об отправках, созданные API. У отчёта без записи об отправке sendId равен null.

Примеры

Отправка из скрипта с собственным ключом идемпотентности. Повторный запуск с тем же --idempotency-key выводит первое письмо с replayed: true вместо того, чтобы отправить второе.

Отправка из скрипта
openemail emails send \  --from 'Acme Billing <[email protected]>' \  --to [email protected] \  --subject 'Your September invoice' \  --html '<p>The invoice is attached. Tell me if anything on it looks wrong.</p>' \  --attachments '[{"fileId":"file_6bb640f5b99e47deb758f1f5"}]' \  --tracking '{"opens":false}' \  --idempotency-key invoice:inv_2026_09_4192 \  --json | jq -r '.id + " " + .status'

Пусть человек прочтёт перевод до отправки. Отправьте одобренный текст как обычные --subject и --html, без --translate, иначе он будет переведён второй раз. Переведённый html уже содержит ваш оригинал под переводом, если вы не передадите --no-include-original.

Предпросмотр перевода и отправка
openemail emails translate --to de \  --subject 'Your September invoice' \  --html "$(cat invoice.html)" \  --json > preview.jsonjq -r .html preview.jsonopenemail emails send --from [email protected] --to [email protected] \  --subject "$(jq -r .subject preview.json)" \  --html "$(jq -r .html preview.json)"

Отправка пакета из файла. Команда завершается с кодом 0 всякий раз, когда пакет был обработан, даже если часть элементов не прошла, поэтому читайте failed и status каждого элемента. Повторный запуск с тем же ключом воспроизводит уже ушедшие элементы и отправляет только остальные, пока массив сохраняет порядок.

receipts.json
[  { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4192", "text": "Thanks for your order." },  { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4193", "text": "Thanks for your order." }]
Отправка пакета
openemail emails send-batch receipts.json --idempotency-key receipts:2026-09-27 --json > result.jsonjq '{ sent, failed }' result.jsonjq -r '.items[] | select(.status == "error") | "\(.index) \(.error.code)"' result.json

Запланируйте письмо, перенесите его и отмените. --yes отвечает на подтверждение, которое спрашивает cancel, чего скрипт сделать не может.

Запланировать, перенести и отменить
ID=$(openemail send --from [email protected] --to [email protected] --subject "Standup notes" \  --body-file notes.md --at 2026-10-01T09:00:00Z --json | jq -r .id)openemail emails reschedule "$ID" 2026-10-01T13:00:00Zopenemail emails get "$ID" --json | jq -r '.status + " " + .scheduledAt'openemail emails cancel "$ID" --yes

Найдите неудавшиеся отправки и прочтите, что случилось с одной из них. При передаче в конвейер без --json --all выводит по одному JSON-объекту в строке.

Поиск неудавшихся отправок
openemail emails list --status failed,partial --from [email protected] --all | jq -r .idopenemail emails get msg_3f9a1c07d2b84e6a9c5b1f20openemail emails list-events msg_3f9a1c07d2b84e6a9c5b1f20 --all --json | jq -r '.items[] | .createdAt + " " + .type'

Прочтите неделю вовлечённости по дням, которые начинаются в полночь по UTC+2, перечислите то, что никто не открыл, и посчитайте клики по каждой ссылке одного письма.

Неделя открытий и кликов
openemail tracking get-stats --days 7 --offset-minutes 120 --json | jq '{ tracked, openRate, clickRate }'openemail tracking list --no-opened --days 7 --all | jq -r .subjectopenemail tracking list-clicks msg_3f9a1c07d2b84e6a9c5b1f20 --all | jq -r .url | sort | uniq -c

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

  • Вход через браузер запрашивает scope на странице одобрения, а openemail login --scopes emails:send,emails:read заранее отмечает оба. Команда, которой не хватает scope, останавливается с кодом выхода 4 и insufficient_scope и называет этот scope.
  • send --attach с файлами больше 5 МБ сначала загружает их в «Файлы», для чего нужен ещё и files:write.
  • Ни одна из этих команд не спрашивает код подтверждения, поэтому вход через браузер выполняет их так же, как API-ключ.
  • emails cancel спрашивает перед отменой, а --yes отвечает за вас. Без присмотра и без --yes она останавливается с Refusing to run unattended. Pass --yes to confirm. и кодом выхода 2.
  • emails send, send-batch и reschedule никогда не спрашивают. send показывает сводку и спрашивает только в терминале, а --yes пропускает и это.
  • --dry-run выводит запрос, который отправила бы команда, ничего не отправляет и завершается с кодом 0. Для emails translate это не тратит ИИ-действие, а emails cancel при этом ничего не спрашивает.

Страницы результатов

emails list, emails list-events, tracking list, list-opens и list-clicks читают одну страницу. --limit задаёт её размер: от 1 до 100, по умолчанию 25, для двух списков emails и от 1 до 200, по умолчанию 50, для трёх списков tracking. --cursor продолжает с курсора, который вывела страница.

  • --all читает все страницы и передаёт элементы потоком: таблицей в терминале и по одному JSON-объекту в строке при передаче в конвейер или с --ndjson.
  • --max <n> останавливается после стольких элементов и подразумевает --all.
  • --json выводит один документ { items, hasMore, nextCursor }, в том числе с --all.
  • Страницы листаются по курсору, а не по смещению, поэтому почта, отправленная, пока вы листаете, никогда не сдвигает и не повторяет строку.

Что полезно знать

  • Каждый запуск создаёт собственный ключ идемпотентности, который покрывает повторы внутри этого запуска. Если запустить отправку дважды, она отправит дважды, если только оба запуска не передают один и тот же --idempotency-key. Тот же ключ с другим телом отклоняется с idempotency_key_reuse и кодом выхода 7.
  • Отменить или перенести можно только почту в состоянии queued и scheduled. Немедленная отправка без окна отмены уходит внутри запроса, так что к тому моменту, когда у вас есть её идентификатор, обычно уже поздно, и вызов завершается с email_not_cancellable и кодом выхода 6.
  • Отменённое письмо остаётся отменённым. Перенос меняет только время, а длительность отсчитывается с момента, когда сервер получил запрос, поэтому, чтобы изменить текст, отмените письмо и отправьте заново.
  • Если перевод невозможно сделать, вся отправка отклоняется, и ничего не уходит без перевода. Пакет с переводом содержит не больше 10 писем с translate.
  • Исчерпанный лимит отправок останавливает отправку с send_quota_exceeded до первого числа месяца, а исчерпанная квота ИИ останавливает перевод с ai_quota_exceeded до полуночи UTC, в обоих случаях с кодом выхода 8.
  • Почта, отправленная с ключом oe_test_, никогда не доставляется. Она получает статус sent с transport, равным test, и никогда не отслеживается.
  • emails get-tracking и tracking get отвечают 404 с кодом выхода 5 для письма, в котором не было ни пикселя, ни переписанной ссылки, потому что «не отслеживалось» не то же самое, что «не открыто». Отслеживание следует настройке, с которой письмо было отправлено, поэтому, если включить его позже, оно не распространится на прежнюю почту.
  • Каждое число это нижняя граница. Читатель, чей почтовый клиент блокирует изображения, никогда не засчитывается как открытие, а клик доказывает прочтение надёжнее, чем открытие.
  • list-opens и list-clicks отвечают 404 для идентификатора msg_, по которому ничего не отслеживалось, но принимают идентификатор tmsg_ как есть, поэтому неизвестный возвращается пустым списком.
  • Ключ, ограниченный некоторыми адресами, видит только почту, отправленную с этих адресов, а ключ, которому выдан целый домен, охватывает каждый адрес на нём.

Все флаги

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

Терминал
openemail emails --helpopenemail emails send --helpopenemail tracking list-opens --help --json

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

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

OpenEmail

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

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