문서로 건너뛰기
CLI

도메인과 주소

도메인을 추가하고 확인하며, 필요한 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-challenge TXT 레코드가 게시되어 있어야 합니다. 그렇지 않으면 호출이 409 domain_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}'
주소 하나를 남기고 catch-all 끄기
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 null
주소 은퇴시키기
address_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:readdomains list, get, list-addresses, get-address
domains:writedomains create, verify, update, delete, create-address, update-address, delete-address
emails:sendaddresses 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이 됩니다. 예약된 계정 주소가 있는 도메인은 409 domain_holds_reserved_addresses입니다.
  • domains create와 두 삭제는 네트워크 실패 후 재시도하지 않습니다. 409 domain_already_added나, 응답을 잃은 뒤 직접 다시 시도했을 때의 404는 첫 시도가 성공했다는 뜻입니다. verify, update, create-address, update-address는 두 번 보내도 결과가 같으므로 알아서 재시도합니다.

다음으로 볼 곳

받은편지함을,
내 방식대로.

기업, AI, 에이전트, 개인 메일을 위한 이메일 인프라. 규모와 프라이버시, 통제권을 위해 만들었습니다. 이메일이 처음부터 갖췄어야 할 모든 것.

OpenEmail

기업, AI, 에이전트, 개인 메일을 위한 이메일 인프라. 규모와 프라이버시, 통제권을 위해 만들었습니다. 이메일이 처음부터 갖췄어야 할 모든 것.

© 2026 OpenEmail. 모든 권리 보유.