Домены и адреса
Добавляйте и подтверждайте домены, читайте нужные им DNS-записи, управляйте адресами на них и проверяйте, от имени каких адресов можно отправлять.
Обзор
Домены охватывают два пространства имён. openemail domains управляет доменами, подключёнными к рабочему пространству: их добавлением и удалением, DNS-записями, нужными каждому, тем, может ли он принимать и отправлять, его catch-all, доменами отслеживания и файлов и адресами на нём. openemail addresses отвечает на более узкий вопрос: от имени каких адресов может отправлять ключ или вход, которым вы пользуетесь.
- Команда домена принимает идентификатор домена, UUID из
domains listилиdomains create. Имя хоста вместо него не принимается, поэтомуopenemail domains get acme.comдаёт 404 и завершается с кодом5. - Команда адреса принимает идентификатор домена, а затем идентификатор адреса, UUID из
domains list-addressesилиdomains create-address. domainиaddressтоже работают как имена пространств имён. Глаголы доменов откликаются на обычные псевдонимы, такие какls,show,new,editиrm, как иaddresses list. У пяти глаголов для адресов на домене, таких какcreate-address, псевдонимов нет.openemail <command> --helpперечисляет каждый аргумент и флаг с типом, scope, который нужен вызову, методом и путём и тем, что возвращается. Добавьте--json, чтобы получить ту же страницу как данные.
Все команды
| Команда | Что делает |
|---|---|
| openemail domains list | Показать домены рабочего пространства по алфавиту с состоянием приёма, отправки, отслеживания и файлов |
| openemail domains get <id> | Прочитать один домен с его адресами, каждой DNS-записью, которую он использует, и тем, найдена ли она, а также с прочтением DMARC |
| openemail domains create --domain <value> | Добавить домен. Ответ содержит каждую DNS-запись для публикации, уже один раз проверенную |
| openemail domains verify <id> | Сразу проверить DNS домена и вернуть домен в том виде, в каком его оставила проверка |
| openemail domains update <id> | Включить или выключить catch-all и задать или убрать домен отслеживания и домен файлов |
| openemail domains delete <id> | Удалить домен и каждый адрес на нём. Просит подтверждения |
| openemail domains list-addresses <id> | Показать адреса на домене с идентификаторами, подписями, состоянием включения и временем, когда каждый последний раз получал почту |
| openemail domains create-address <id> --local-part <value> | Создать на домене включённый адрес с необязательным --label |
| openemail domains get-address <id> <address-id> | Прочитать один адрес на домене |
| openemail domains update-address <id> <address-id> | Переименовать адрес через --label или выключить и включить его через --no-enabled и --enabled |
| openemail domains delete-address <id> <address-id> | Удалить адрес с его домена. Просит подтверждения |
| openemail addresses list | Показать адреса, от имени которых можно отправлять с этим ключом или входом, и состояние приёма и отправки каждого домена |
Все флаги есть в справке своей команды, например openemail domains update --help или openemail domains create-address --help.
Приём и отправка
Домен сообщает о двух независимых фактах. receiving.verified становится true, когда публичный DNS отвечает его MX-записями и TXT-записью _openemail-challenge, и с этого момента он принимает почту. sending.status это состояние подписи, каким его увидела последняя проверка: verified, pending, failed, no_identity или unknown. sending.canSend говорит, была бы отправка с домена принята прямо сейчас, а отрицательный вердикт старше суток считается неизвестным, поэтому скрипту стоит ветвиться по canSend, а не по status. Пока он false, отправка с домена отклоняется с 409 domain_not_sendable.
domains createвыполняет первую проверку DNS во время вызова, поэтому у каждой записи вrecordsуже естьstatus:found,missingили null, если её ещё не проверяли. Публикуйте каждую запись ровно в том виде, в каком она дана, поскольку значения свои у каждого домена.domains verifyпроверяет сразу. В течение 10 секунд после последней проверки она ничего нового не проверяет и возвращает домен как есть. На подтверждённом домене она снова проверяет записи подписи, поэтомуsendingсвежий.domains getна неподтверждённом домене проверяет снова, если последней проверке больше 20 секунд, поэтому опросgetтоже работает, и ему нужен толькоdomains:read, тогда какverifyнуженdomains:write.- Запись, опубликованная только что, может появиться в публичном DNS через несколько минут.
В терминале get, create и verify выводят по одному полю в строке, а вложенные блоки, такие как receiving, sending и records, в виде компактного JSON. Добавьте --json и читайте их инструментом вроде jq, как в примерах ниже.
Catch-all, домены отслеживания и файлов
domains update меняет три настройки, которые не зависят друг от друга. Флаг, который вы не указали, остаётся нетронутым, а без флагов домен возвращается без изменений.
| Флаг | Что меняет |
|---|---|
| --catch-all, --no-catch-all | Включённый принимает почту на любой адрес на домене, который никто не создавал, и адрес появляется в list-addresses с первого письма. Выключенный отклоняет почту на каждый адрес, созданный не вручную, включая те, что catch-all подхватил раньше. Новый домен начинает с включённым |
| --tracking-host <value> | Поддомен, например links.acme.com, для отслеживаемых ссылок и пикселя открытия. null убирает его |
| --storage-host <value> | Поддомен, например files.acme.com, для ссылок на скачивание файлов, отправленных с домена. null убирает его |
- Новый хост сохраняется и проверяется в том же вызове. Опубликуйте CNAME-запись с именем
record.nameи значениемrecord.valueиз блокаtrackingилиstorageответа, с выключенным проксированием. Повторная настройка хоста может дать ему другое значение, поэтому публикуйте то, о котором сообщает последний ответ. - Пока проверка не пройдена, хост в состоянии
pending, и новая почта продолжает использовать хост OpenEmail по умолчанию. Когда проверка проходит, он становитсяactive. OpenEmail продолжает проверять сам, и активный хост, который трижды подряд не прошёл проверку или последняя успешная проверка которого была 2 часа назад, становитсяfailed, а новая почта возвращается на хост по умолчанию. - Убирайте хост через
null, как в--tracking-host null. Пустое значение, например--tracking-host=, в CLI считается ошибкой использования и завершается с кодом2. - Новому хосту нужен подтверждённый домен или хотя бы опубликованная TXT-запись
_openemail-challenge. Иначе вызов отклоняется с 409domain_not_verified. - Флаги применяются по порядку: catch-all, затем домен отслеживания, затем домен файлов. Если более поздний флаг отклонён, более раннее изменение может остаться сохранённым, поэтому отправляйте их отдельными вызовами, когда каждое должно действовать само по себе.
Адреса на домене
Домен содержит адреса, созданные вручную или через API, и те, что его catch-all подхватил, когда на них впервые пришла почта. list-addresses показывает оба вида, включая выключенные. Сам catch-all строкой не является: это receiving.catchAll домена.
create-addressпринимает--local-part, часть перед @, и необязательный--label. Домен не обязан быть уже подтверждён, но адрес ничего не получает, пока он не подтверждён. Одиночная*отклоняется, потому что так записывается catch-all.- Создание адреса, который уже существует или был удалён, не ошибка. Он возвращается включённым, с переданной подписью или без неё, и сохраняет свой идентификатор. Адрес, подхваченный catch-all, становится созданным вручную, поэтому продолжает принимать почту после выключения catch-all.
- При включённом catch-all новый адрес начинает с настроек catch-all для отдельного адреса, таких как подпись и отслеживание, кроме настроек конфиденциальности. Они копируются один раз и не синхронизируются.
update-address --no-enabledпрекращает приём почты на адрес, так что отправители получают отказ, и с него ничего нельзя отправить. Он сохраняет свою почту, настройки и людей, у которых есть к нему доступ, а--enabledпродолжает с того же места.--labelпереименовывает его, а--label nullубирает имя.delete-addressидёт дальше. Почта на адрес отклоняется даже при включённом catch-all, его пересылка прекращается, его настройки удаляются, люди, которым дали к нему доступ, этот доступ теряют, а вход по паролю отзывается. Уже полученная почта остаётся в ящике. Повторное создание возвращает тот же идентификатор, но без старых настроек и доступа.
От имени каких адресов можно отправлять
openemail addresses list отвечает на вопрос, стоящий за 403 from_address_forbidden: какие адреса ключ или вход, которым вы вызываете, может ставить в From. Ей нужен emails:send, а не scope чтения, потому что она описывает, что приняла бы отправка.
- В терминале она выводит две таблицы: адреса, с тем, включён ли каждый и можно ли с него отправлять, а затем домены, с тем, подтверждён ли каждый для приёма и для отправки, и с его catch-all.
unrestrictedравен true, когда учётные данные ничем не сужены. Тогда отправлять можно с любой локальной части на доменах рабочего пространства, включая те, что никто не создавал. ИначеcanSendравен true только для включённого адреса, который покрывают учётные данные, через выданный им целый домен или собственный список адресов.canSendравен false для выключенного адреса, для адреса, который учётные данные не покрывают, и для адреса, домен которого ещё не может подписывать.- Перечисляются только созданные адреса. Учётные данные, которым выдан целый домен, всё равно могут отправлять с любой локальной части на нём, а с адреса из их списка, за которым нет ящика, можно отправлять, хотя здесь он не появится.
- С
--jsonона выводит{ unrestricted, addresses, domains, hasMore, nextCursor }для одной страницы и{ unrestricted, addresses, domains }с--allвместо документа{ items, hasMore, nextCursor }, который выводят другие списки. С--allв конвейере или с--ndjsonона выводит по одному адресу в строке.
status, open и DNS-провайдеры
openemail status одновременно читает ваш вход, addresses list и domains list и выводит их вместе. Её таблица Sender addresses показывает каждый адрес с тем, может ли он отправлять и включён ли он. Её таблица Domains показывает каждый домен как verified или not verified для приёма, его статус отправки и его catch-all. Она показывает первые 100 записей каждого вида и называет команду с --all для остальных.
- Часть, которую ваши учётные данные не могут прочитать, например домены без
domains:readили адреса безemails:send, пишет Not available с причиной, а остальное всё равно выводится. - Если адресов ещё нет, она предлагает
openemail domains create --domain example.com. openemail status --jsonвыводит один объект сaccount,addresses,domainsиunavailable, гдеunavailableдаёт причину для каждой части, которую не удалось прочитать.
Подключение DNS-провайдера, чтобы записи нового домена писались за вас, в 0.0.2 выполняется только в веб-приложении. openemail open providers или open dns открывает эту страницу. open domains открывает домены и их DNS-записи, а open addresses адреса. Пересылка тоже в веб-приложении, и open forwarding <address> открывает её для одного адреса. --print выводит ссылку вместо того, чтобы открывать браузер.
Там, где OpenEmail сама записала DNS домена, domains delete забирает эти записи обратно и перечисляет в leftBehind те, которые не смогла, чтобы вы удалили их у своего DNS-провайдера. Записи, которые вы опубликовали сами, никогда не трогаются, поэтому удалите и их, когда домена не станет.
Примеры
openemail domains create --domain acme.com --json > acme.jsonjq -r '.records[] | [.type, .name, .value, (.priority // "")] | @tsv' acme.jsonopenemail domains verify "$(jq -r .id acme.json)"id=b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6funtil openemail domains get "$id" --json | jq -e .receiving.verified > /dev/null; do sleep 30doneopenemail domains get "$id" --json | jq '.sending | {status, canSend, error}'openemail domains list-addresses "$id" --allopenemail domains create-address "$id" --local-part invoices --label Invoicesopenemail domains update "$id" --no-catch-all --dry-runopenemail domains update "$id" --no-catch-allСозданный вручную invoices продолжает принимать почту после выключения catch-all, а почта на каждый другой адрес, подхваченный catch-all, отклоняется. Пробный запуск выводит PATCH и его тело, не отправляя его.
openemail domains update "$id" --tracking-host links.acme.com --json | jq '.tracking | {status, record, error}'openemail domains update "$id" --tracking-host nulladdress_id=$(openemail domains list-addresses "$id" --all | jq -r 'select(.address == "[email protected]") | .id')openemail domains update-address "$id" "$address_id" --no-enabledopenemail domains delete-address "$id" "$address_id" --yesВыключение адреса сначала можно отменить через --enabled. Удаление отменить нельзя, и в скрипте ему нужен --yes. При входе через браузер оно ещё и спрашивает код подтверждения, который --yes никогда не пропускает.
openemail domains list --all | jq -r 'select(.sending.canSend | not) | [.domain, .sending.status] | @tsv'openemail addresses list --all --json | jq -r '.addresses[] | select(.canSend) | .address'Scope, подтверждения и ошибки
| Scope | Команды |
|---|---|
| domains:read | domains list, get, list-addresses, get-address |
| domains:write | domains create, verify, update, delete, create-address, update-address, delete-address |
| emails:send | addresses list |
- Вход или ключ без нужного scope останавливается с кодом выхода
4, называет недостающий scope и объясняет, как его получить. domains deleteиdomains delete-addressпросят подтверждения. Ответ «нет» завершает их с кодом10и ничего не меняет. Без присмотра и без--yesони останавливаются с кодом выхода2до любой отправки.- При входе через браузер эти два удаления ещё и спрашивают код подтверждения, как веб-приложение. Без присмотра ввести его некому, поэтому команда останавливается с кодом выхода
4. Сначала запуститеopenemail verify, и следующие 60 минут код не понадобится. У API-ключа код не спрашивают никогда. --dry-runвыводит запрос, который отправило бы изменение, с его телом и завершается с кодом0, не отправляя его и не прося подтверждения.- Список читает одну страницу:
--limitпринимает от 1 до 100, а если его не указать, сервер отдаёт 25, и--cursorпринимаетnextCursorпредыдущей страницы.--allчитает все страницы,--max <n>останавливается после стольких элементов, а--ndjsonили--allв конвейере выводит по одному JSON-объекту в строке. С--jsondomains listиlist-addressesвыводят один документ{ items, hasMore, nextCursor }. - Ключ или вход, ограниченный определёнными доменами или адресами, всё равно видит каждый домен и адрес. Добавить домен он не может, а для любого другого изменения нужно, чтобы весь домен был среди выданных ему доменов, иначе вызов отклоняется с 422
capability_unsupported. - Отказ завершается кодом своего статуса:
4для 403, напримерdomain_allowance_reached, когда тариф больше не разрешает доменов,5для 404,6для 409, напримерdomain_already_addedилиdomain_claimed, и7для 422, напримерinvalid_tracking_hostилиworkspace_limit_reached. - Последний домен рабочего пространства нельзя удалить из CLI. Это 409
last_domain, потому что его удаление стирает весь почтовый ящик, а веб-приложение сначала просит это подтвердить. Домен с зарезервированными адресами аккаунта даёт 409domain_holds_reserved_addresses. domains createи два удаления никогда не повторяются после сбоя сети. 409domain_already_addedили 404 при вашей собственной второй попытке после потерянного ответа означает, что первая сработала.verify,update,create-addressиupdate-addressповторяются сами, поскольку двойная отправка даёт тот же результат.