도메인과 주소
도메인을 추가하고 확인하며, 필요한 DNS 레코드를 읽고, 도메인의 주소를 관리하고, 어떤 주소로 보낼 수 있는지 확인합니다.
개요
두 네임스페이스가 도메인을 다룹니다. openemail domains는 워크스페이스에 연결된 도메인을 관리합니다. 추가와 제거, 도메인마다 필요한 DNS 레코드, 수신과 발송 가능 여부, catch-all, 추적 도메인과 파일 도메인, 그리고 도메인의 주소입니다. openemail addresses는 더 좁은 질문에 답합니다. 지금 쓰는 키나 로그인이 어떤 주소로 보낼 수 있는지입니다.
- 도메인 명령은 도메인 ID를 받으며, 이는
domains list나domains create에서 얻는 UUID입니다. 대신 호스트 이름은 받지 않으므로openemail domains get acme.com은 404이고 종료 코드5로 끝납니다. - 주소 명령은 도메인 ID와 그다음 주소 ID를 받으며, 주소 ID는
domains list-addresses나domains create-address에서 얻는 UUID입니다. domain과address도 네임스페이스 이름으로 쓸 수 있습니다. 도메인 동사는ls,show,new,edit,rm같은 흔한 별칭을 받으며,addresses list도 마찬가지입니다.create-address같은 도메인 주소용 동사 다섯 개에는 별칭이 없습니다.openemail <command> --help는 모든 인수와 플래그를 타입, 호출에 필요한 범위, 메서드와 경로, 반환값과 함께 나열합니다.--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> | 도메인의 주소를 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는 공개 DNS가 MX 레코드와 _openemail-challenge TXT 레코드로 응답하면 true가 되고, 그때부터 메일을 받습니다. sending.status는 마지막 확인에서 본 서명 상태로 verified, pending, failed, no_identity, unknown 중 하나입니다. sending.canSend는 지금 그 도메인에서 보내면 받아들여질지 알려 주며, 하루보다 오래된 부정 판정은 알 수 없음으로 간주하므로, 스크립트는 status가 아니라 canSend로 분기해야 합니다. 이 값이 false인 동안 그 도메인에서 보내면 409 domain_not_sendable로 거부됩니다.
domains create는 호출 중에 첫 DNS 확인을 하므로records의 각 항목에는 이미status가 있습니다.found,missing, 또는 아직 확인하지 않았으면 null입니다. 값은 도메인마다 다르므로 모든 레코드를 받은 그대로 게시하세요.domains verify는 바로 확인합니다. 마지막 확인 후 10초 안에는 새로 확인하지 않고 도메인을 현재 상태 그대로 반환합니다. 확인된 도메인에서는 서명 레코드를 다시 확인하므로sending이 최신 상태가 됩니다.- 확인되지 않은 도메인에서
domains get은 마지막 확인이 20초보다 오래되었으면 다시 확인합니다. 그래서get을 폴링해도 되며,verify에는domains:write가 필요하지만get에는domains:read만 있으면 됩니다. - 방금 게시한 레코드가 공개 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은 제거합니다 |
- 새 호스트는 같은 호출에서 저장되고 확인됩니다. 응답의
tracking또는storage블록에 있는record.name을 이름으로,record.value를 값으로 하는 CNAME 레코드를 프록시를 끈 채 게시하세요. 호스트를 다시 설정하면 값이 달라질 수 있으므로 가장 최근 응답이 알려 준 값을 게시하세요. - 확인을 통과하기 전까지 호스트는
pending이고 새 메일은 기본 OpenEmail 호스트를 계속 씁니다. 통과하면active가 됩니다. OpenEmail은 알아서 계속 확인하며, 활성 호스트가 세 번 연속 확인에 실패하거나 마지막 통과가 2시간 전이면failed가 되고 새 메일은 기본 호스트로 돌아갑니다. --tracking-host null처럼null로 호스트를 제거합니다.--tracking-host=같은 빈 값은 CLI에서 사용 오류이며 종료 코드2로 끝납니다.- 새 호스트에는 도메인이 확인되어 있거나, 최소한
_openemail-challengeTXT 레코드가 게시되어 있어야 합니다. 그렇지 않으면 호출이 409domain_not_verified로 거부됩니다. - 플래그는 catch-all, 추적 도메인, 파일 도메인 순서로 적용됩니다. 뒤의 플래그가 거부되어도 앞의 변경은 저장된 채 남을 수 있으므로, 각각 따로 성립해야 한다면 별도의 호출로 보내세요.
도메인의 주소
도메인에는 직접 또는 API로 만든 주소와, 처음 메일이 도착했을 때 catch-all이 받아들인 주소가 있습니다. list-addresses는 사용 중지된 것까지 두 종류를 모두 보여 줍니다. catch-all 자체는 행이 아니라 도메인의 receiving.catchAll입니다.
create-address는 @ 앞부분인--local-part와 선택 사항인--label을 받습니다. 도메인이 아직 확인되지 않아도 되지만, 확인될 때까지 주소는 아무것도 받지 않습니다.*하나만 주면 거부되는데, 그것이 catch-all을 쓰는 방식이기 때문입니다.- 이미 있거나 제거된 주소를 만드는 것은 오류가 아닙니다. 보낸 라벨이나 라벨 없이 사용 상태로 돌아오며, ID는 유지됩니다. catch-all이 받아들인 주소는 직접 만든 주소가 되므로, catch-all을 꺼도 계속 메일을 받습니다.
- catch-all이 켜져 있으면 새 주소는 개인정보 설정을 제외한 catch-all의 주소별 설정, 예를 들어 서명과 추적 설정을 이어받아 시작합니다. 설정은 한 번 복사될 뿐 계속 맞춰지지는 않습니다.
update-address --no-enabled는 주소가 메일을 받지 않게 해서 보내는 사람은 반송을 받고, 그 주소에서는 아무것도 보낼 수 없습니다. 메일, 설정, 접근할 수 있는 사람은 유지되며,--enabled로 멈춘 곳부터 다시 시작합니다.--label은 이름을 바꾸고,--label null은 이름을 지웁니다.delete-address는 더 나아갑니다. catch-all이 켜져 있어도 그 주소로 온 메일은 거부되고, 전달이 멈추고, 설정이 삭제되고, 접근 권한을 받은 사람은 권한을 잃으며, 비밀번호 로그인이 폐기됩니다. 이미 받은 메일은 메일함에 남습니다. 다시 만들면 같은 ID로 돌아오지만 옛 설정이나 접근 권한은 없습니다.
어떤 주소로 보낼 수 있는지
openemail addresses list는 403 from_address_forbidden의 원인이 되는 질문에 답합니다. 지금 호출에 쓰는 키나 로그인이 From에 어떤 주소를 넣을 수 있는지입니다. 보내기가 무엇을 받아들일지 설명하는 명령이므로 읽기 범위가 아니라 emails:send가 필요합니다.
- 터미널에서는 표 두 개를 출력합니다. 먼저 각 주소가 사용 상태인지와 그 주소에서 보낼 수 있는지를, 그다음 각 도메인이 수신과 발송에 대해 확인되었는지와 catch-all을 보여 줍니다.
- 자격 증명이 아무것으로도 좁혀지지 않았으면
unrestricted가 true입니다. 그러면 워크스페이스 도메인의 어떤 local-part로든, 아무도 만들지 않은 것까지 보낼 수 있습니다. 그렇지 않으면canSend는 자격 증명이 가진 도메인 전체나 자체 주소 목록으로 다루는 사용 상태의 주소에만 true입니다. - 사용 중지된 주소, 자격 증명이 다루지 않는 주소, 도메인이 아직 서명할 수 없는 주소에서는
canSend가 false입니다. - 만들어진 주소만 나열됩니다. 도메인 전체를 가진 자격 증명은 그 도메인의 어떤 local-part로든 보낼 수 있으며, 목록에 있지만 메일함이 없는 주소는 여기 나타나지 않아도 보낼 수 있습니다.
--json을 주면 다른 목록이 출력하는{ items, hasMore, nextCursor }문서 대신, 한 페이지에 대해{ unrestricted, addresses, domains, hasMore, nextCursor }를,--all과 함께면{ unrestricted, addresses, domains }를 출력합니다. 파이프에서--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-allinvoices를 직접 만들어 두면 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'범위, 확인, 오류
| 범위 | 명령 |
|---|---|
| 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 |
- 범위가 없는 로그인이나 키는 종료 코드
4로 멈추고, 빠진 범위와 그것을 얻는 방법을 알려 줍니다. 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 객체 하나를 출력합니다.--json을 주면domains list와list-addresses는{ items, hasMore, nextCursor }문서 하나를 출력합니다. - 특정 도메인이나 주소로 제한된 키나 로그인도 모든 도메인과 주소를 봅니다. 도메인을 추가할 수는 없으며, 그 밖의 모든 변경에는 그 도메인 전체가 자신이 가진 도메인에 들어 있어야 하고, 그렇지 않으면 호출이 422
capability_unsupported로 거부됩니다. - 거부는 상태에 맞는 코드로 종료합니다. 403이면
4이며, 요금제가 더 이상 도메인을 허용하지 않을 때의domain_allowance_reached가 그 예입니다. 404면5, 409면6이며domain_already_added나domain_claimed가 그 예입니다. 422면7이며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는 두 번 보내도 결과가 같으므로 알아서 재시도합니다.