Цепочки, черновики и метки
Каждая команда пространств имён threads, drafts и labels и то, как они лежат под inbox, read, archive и другими почтовыми командами.
Обзор
Почтовые команды, такие как inbox, read, archive и label add, написаны для людей: они принимают сразу несколько идентификаторов цепочек, форматируют вывод и прячут идентификаторы меток. Каждая из них выполняет команды с этой страницы, то есть методы SDK для цепочек, черновиков и меток, по одной команде на метод, поэтому threads.listAttachments становится openemail threads list-attachments.
Пользуйтесь ими, когда нужно то, что почтовые команды опускают: цепочка ровно в том виде, в каком её возвращает API, файлы письма, черновики, а также создание, переименование, перекраска и удаление меток.
openemail threadиopenemail draftработают так же, как имена во множественном числе. Уopenemail labelsформы единственного числа нет:openemail labelэто почтовая команда, которая ставит метки на цепочки.- Глаголы принимают обычные псевдонимы:
lsдляlist,showиviewдляget,newиaddдляcreate,editдляupdate, а такжеrm,delиremoveдляdelete. - Все флаги есть в
openemail <namespace> <verb> --help, напримерopenemail threads list --help.
Цепочки
Разговоры в почтовом ящике. Идентификатор цепочки, например CAHk7pQ2x9LmZ4, берётся из threads list, openemail inbox или openemail search.
| Команда | Что делает |
|---|---|
| openemail threads list | Показать одну страницу цепочек в папке, новые сверху. Каждая строка это только идентификатор. --folder, --query, --label-ids, --sort, --date-from, --date-to и --from-contacts сужают и упорядочивают её |
| openemail threads get <id> | Прочитать цепочку со всеми её письмами, старые сверху, с метками и признаком непрочитанности |
| openemail threads update <id> | Отметить цепочку прочитанной через --read или непрочитанной через --no-read, а также ставить и снимать метки через --add-label-ids и --remove-label-ids, до 50 каждого вида |
| openemail threads trash <id> | Переместить цепочку в корзину, за один шаг убрав её из входящих, спама, отложенных и архива. Просит подтверждения |
| openemail threads snooze <id> <wake-at> | Скрыть цепочку до момента в будущем, например 2026-10-01T09:00:00Z. Повторное откладывание заменяет время возврата |
| openemail threads unsnooze <id> | Вернуть отложенную цепочку во входящие сейчас и сбросить время возврата |
| openemail threads list-attachments <id> <message-id> | Показать вложения одного письма, у каждого байты встроены в base64 в content |
--folderпо умолчанию равенinboxи сопоставляется как идентификатор метки, поэтому работаютsent,archive,spam,trash,draft,snoozed,starredиunread,binчитается какtrash, а также работает идентификатор пользовательской метки, напримерUSER_RECEIPTS. Папка, которой ничего не соответствует, возвращает пустую страницу, а не ошибку.--queryпринимает синтаксис поиска приложения, аin:anywhereищет во всех папках.--label-idsсужает ещё сильнее, поскольку цепочка должна нести и папку, и каждый переданный идентификатор.--date-fromи--date-toсмотрят на самое новое письмо каждой цепочки, и обе границы включаются.threads getвключает в письма неотправленные черновики ответов с пометкойisDraft: trueи открывает также идентификатор черновика.threads updateнужен--read,--no-readили метка, которую нужно поставить или снять. Снятие применяется до добавления. Идентификатор метки, которой нет, отклоняется сlabel_not_found, и в цепочке ничего не меняется, поэтому сначала создайте метку.TRASH,SNOOZEDиDRAFTотклоняются сlabel_not_directly_settable: используйтеthreads trashиthreads snooze.threads trashничего не удаляет, и цепочку по-прежнему можно прочитать черезthreads get, но ни одна команда не достаёт цепочку из корзины. Если отправить в корзину отложенную цепочку, её возврат тоже отменяется.threads snoozeотправляет<wake-at>как есть, поэтому передайте момент в будущем в ISO 8601 сZили смещением: время без них читается в часовом поясе сервера. Задержка вроде3hотклоняется как неверная. Задержку принимаетopenemail snooze --until 3h. Цепочки возвращаются при ежечасном обходе, с опозданием примерно до часа, и всегда во входящие.threads list-attachmentsвозвращает каждый файл целиком в одном ответе. Идентификатор письма берите изmessagesв выводеthreads get. Если сохранённые байты не найдены,contentэто пустая строка, поэтому проверяйте длину перед декодированием.
Черновики
Неотправленные письма, сохранённые в ящике. Идентификатор черновика начинается с draft-.
| Команда | Что делает |
|---|---|
| openemail drafts list | Показать одну страницу черновиков, недавно сохранённые сверху. Каждая строка это только идентификатор, а --query ищет по ним |
| openemail drafts get <id> | Прочитать получателей черновика, тему, тело, отправителя, цепочку, на которую он отвечает, и имена его вложений |
| openemail drafts create | Сохранить новый черновик из --to, --cc, --bcc, --subject, --html, --text, --from и --thread-id, все необязательны |
| openemail drafts update <id> | Изменить поля сохранённого черновика. Поле, которое вы не указали, сохраняет своё значение |
| openemail drafts delete <id> | Удалить черновик навсегда. В корзину он не попадает. Просит подтверждения |
drafts list --queryищет по теме, отправителю и началу тела и никогда не выходит за пределы черновиков.older_than:30dи другие операторы даты смотрят на время последнего сохранения черновика, аto:,cc:иbcc:в черновике ничему не соответствуют.- Черновик хранится как цепочка с меткой
DRAFT, поэтомуthreads getоткрывает его, аopenemail inbox draftперечисляет черновики.drafts get,updateиdeleteотклоняют идентификатор обычной цепочки с 404. openemail drafts createбез флагов сохраняет пустой черновик. Проверяются только длины: тема до 998 символов, а--htmlи--textдо 1 000 000 каждый, причём если заданы оба, сохраняется--html. Флага для вложений нет.drafts updateзаменяет каждое переданное поле. Список заменяет сохранённый целиком, поэтому--toс одним адресом убирает остальные, а обновление очищает список вложений черновика.--thread-idзаписывает цепочку, на которую отвечает черновик, но сам черновик всё равно хранится как отдельная цепочка.- Повторный запуск
drafts createсохраняет второй черновик, потому что команда не принимает ключ идемпотентности. Отображаемое имя с запятой распадается на двух испорченных получателей, поэтому не ставьте в нём запятую. openemail send --draft <id> --to <address>отправляет черновик. Тело берётся из черновика, как и тема, если вы не передали--subject, а получатели те, кого вы указали. Её нельзя сочетать с телом,--templateили--translate.
Метки
Метки, которые может нести цепочка. Идентификатор пользовательской метки это USER_ и имя, с которым она создана, в верхнем регистре, где каждая группа пробелов заменена на _, поэтому Big Clients становится USER_BIG_CLIENTS.
| Команда | Что делает |
|---|---|
| openemail labels list | Показать пользовательские метки рабочего пространства, по имени, каждую с цветом, threadCount, createdAt и updatedAt |
| openemail labels list-colors | Показать палитру приложения: четырнадцать сплошных цветов и семь градиентов. Цветом передаётся value |
| openemail labels get <id> | Прочитать одну пользовательскую метку, идентификатор сопоставляется с учётом регистра |
| openemail labels create --name <value> | Создать пользовательскую метку. --color-background-color задаёт ей цвет |
| openemail labels update <id> | Переименовать или перекрасить метку. Идентификатор остаётся прежним, как и цепочки, которые её несут |
| openemail labels delete <id> | Удалить метку и снять её со всех цепочек, которые её несли. Просит подтверждения |
- Идентификатор никогда не меняется, даже после переименования, поэтому храните идентификаторы, а не имена.
- Системные метки, такие как
INBOX,STARREDиUNREAD, не перечисляются, их нельзя изменить или удалить, хотяthreads updateих принимает.labels getдля такой метки возвращает 404. - В рабочем пространстве может быть до 50 пользовательских меток. Имя, которое уже есть у другой метки без учёта регистра, отклоняется с
label_name_taken. - Цвет это шестнадцатеричное значение, например
#3B82F6, или токен градиента, напримерgradient:sunset.--label-colorпринимает весь цвет в виде JSON, а--label-color nullего сбрасывает. - Метка принадлежит рабочему пространству, поэтому переименование, перекраска или удаление меняет её для всех в нём.
- У
labels deleteнет отмены. Если снова создать метку с тем же именем, получится тот же идентификатор, но цепочкам она не вернётся.threadCountвlabels getговорит, сколько разговоров её лишится.
Как ими пользуются почтовые команды
| Почтовая команда | Что она выполняет |
|---|---|
| inbox [folder] | threads list для одной страницы, затем threads get для каждой цепочки, по шесть за раз |
| search <query...> | threads list --query, затем threads get для каждой цепочки |
| read <thread-id> | threads get, затем threads update --read, если вы не передали --no-mark-read |
| reply <thread-id> | threads get для получателей, темы и адреса отправки, затем emails send в эту цепочку |
| archive <thread-id...> | threads update --add-label-ids ARCHIVE --remove-label-ids INBOX |
| unarchive <thread-id...> | threads update --add-label-ids INBOX --remove-label-ids ARCHIVE |
| star, unstar <thread-id...> | threads update, который ставит или снимает STARRED |
| mark read, unread <thread-id...> | threads update --read или --no-read |
| trash <thread-id...> | threads trash |
| snooze <thread-id...> --until <when> | threads snooze, причём задержка вроде 3h сначала превращается в момент времени |
| unsnooze <thread-id...> | threads unsnooze |
| label add, remove <thread-id...> | threads update --add-label-ids или --remove-label-ids |
| send --draft <id> | emails send --draft-id |
- Почтовая команда принимает несколько идентификаторов цепочек и отчитывается по каждому, а с
--jsonвыводит{ results, succeeded, failed }. Команда с этой страницы принимает один идентификатор и выводит то, что возвращает API. openemail inboxчитает каждую цепочку, которую перечисляет, чтобы показать, кто писал последним, и тему.threads listделает один запрос на страницу и выводит только идентификаторы, а конвейеру больше ничего и не нужно.openemail readпревращает HTML-письмо в текст и отмечает цепочку прочитанной.threads getвыводит цепочку так, как её возвращает API, и ничего не меняет.
Примеры
Отметить цепочку прочитанной, отправить в архив и поставить метку одним запросом там, где mark read, archive и label add сделали бы три:
openemail threads update CAHk7pQ2x9LmZ4 --read --add-label-ids ARCHIVE,USER_RECEIPTS --remove-label-ids INBOX --jsonСоздать метку и разложить под неё каждую подходящую цепочку. В конвейере --all выводит по одному JSON-объекту в строке:
openemail labels create --name Receipts --color-background-color gradient:meadowopenemail threads list --query "in:anywhere subject:receipt newer_than:1y" --all | jq -r .id | xargs openemail label add --label USER_RECEIPTSСохранить один файл из письма. Идентификаторы писем есть в messages вывода threads get:
openemail threads get CAHk7pQ2x9LmZ4 --json | jq -r ".messages[].id"openemail threads list-attachments CAHk7pQ2x9LmZ4 message_4c1b257a --json | jq -r '.[] | select(.filename == "invoice.pdf") | .content' | base64 --decode > invoice.pdfНаписать черновик, изменить его, прочитать обратно и отправить:
DRAFT=$(openemail drafts create --to [email protected] --subject "Engine notes for Thursday" --html "<p>Agenda below.</p>" --json | jq -r .id)openemail drafts update "$DRAFT" --to [email protected],[email protected]openemail drafts get "$DRAFT"openemail send --draft "$DRAFT" --from [email protected] --to [email protected],[email protected]Убрать черновики, которые никто не сохранял 30 дней. Пробный запуск выводит каждый DELETE, не отправляя его, а --yes отвечает на подтверждение:
openemail drafts list --query older_than:30d --all | jq -r .id > stale.txtxargs -n 1 openemail drafts delete --dry-run < stale.txtxargs -n 1 openemail drafts delete --yes < stale.txtВыбрать градиент из палитры, посмотреть изменение заранее, применить его, а позже снова снять цвет:
openemail labels list-colors --json | jq -r '.[] | select(.kind == "gradient") | .value'openemail labels update USER_RECEIPTS --name "Receipts 2026" --color-background-color gradient:aurora --dry-runopenemail labels update USER_RECEIPTS --name "Receipts 2026" --color-background-color gradient:auroraopenemail labels update USER_RECEIPTS --label-color nullScope и коды подтверждения
| Scope | Команды |
|---|---|
| threads:read | threads list, get и list-attachments |
| threads:write | threads update, trash, snooze и unsnooze |
| drafts:read | drafts list и get |
| drafts:write | drafts create, update и delete |
| labels:read | labels list, list-colors и get |
| labels:write | labels create, update и delete |
Без нужного scope команда останавливается с кодом выхода 4. Ни одна из этих команд не спрашивает код подтверждения, ни при входе через браузер, ни с API-ключом.
Вход или ключ, ограниченный некоторыми адресами, видит только цепочки, доставленные на них, а любая другая цепочка даёт 404, как будто её нет. Метки принадлежат рабочему пространству, поэтому он всё равно видит каждую метку, но threadCount считает только разговоры, которые ему видны.
Страницы, подтверждения и пробные запуски
threads list,drafts listиlabels listчитают одну страницу: 25 элементов, если--limitне говорит иначе, и до 100.--cursorпродолжает с курсора, который вывела страница. Курсор цепочек сохраняет порядок, в котором он был выдан, поэтому передавайте с ним те же фильтры.--allчитает все страницы, а--max <n>останавливается после стольких элементов. В конвейере или с--ndjsonвыводится по одному JSON-объекту в строке, а с--jsonодин документ{ items, hasMore, nextCursor }.hasMoreможет быть true на странице, которая оказывается последней, и тогда следующий вызов не возвращает элементов. Цепочка, получившая новую почту, пока вы листаете, уходит вперёд курсора и не возвращается следующими страницами, как и черновик, сохранённый, пока вы листаете.threads trash,drafts deleteиlabels deleteпросят подтверждения. Без присмотра, с--json,--no-inputили без терминала, они останавливаются с кодом выхода2и ничего не меняют, если вы не передадите--yes.--dry-runвыводит запрос, который отправила бы команда, со скрытыми учётными данными и завершается с кодом0, не отправляя его и не прося подтверждения. С--jsonвыводится{ dryRun, request }.
Тела JSON и очистка поля
--data принимает всё тело в виде JSON: встроенно, из файла через @path или из stdin через -, а флаг, переданный вдобавок, переопределяет свой ключ.
Пустое значение флага это ошибка использования, поэтому поле, которое очищается пустым значением, передаётся через --data. --label-color null сбрасывает цвет метки.
openemail drafts update draft-5f0c2a9e-8b1d-4e7a-a3c6-2d9f41b7e0c8 --data '{"from":""}'openemail drafts update draft-5f0c2a9e-8b1d-4e7a-a3c6-2d9f41b7e0c8 --data '{"threadId":""}'openemail drafts update draft-5f0c2a9e-8b1d-4e7a-a3c6-2d9f41b7e0c8 --data '{"to":[]}'openemail drafts create --data @draft.json --subject "Overrides the file"Первая сохраняет черновик без отправителя, вторая отвязывает его от цепочки, на которую он отвечал, а третья очищает его получателей.
Все флаги
openemail threads --helpopenemail threads list --helpopenemail drafts create --help --jsonopenemail <namespace> <verb> --help показывает каждый аргумент и флаг с типом, scope, которые нужны вызову, его метод и путь, что он возвращает, и примечания из справочника API. Добавьте --json, чтобы получить ту же справку как данные.