문서로 건너뛰기
SDK

목록과 단건 조회

`emails.list`, `emails.listAll`, `emails.iterate`, `emails.get`, `emails.listEvents`.

emails.list

list-emails.ts
const first = await openemail.emails.list({  status: ['queued', 'scheduled'],  from: '[email protected]',  limit: 50,}) const second = first.nextCursor  ? await openemail.emails.list({ status: ['queued', 'scheduled'], limit: 50, cursor: first.nextCursor })  : null

페이지는 { items, hasMore, nextCursor }입니다. 그다음 페이지를 받으려면 같은 필터와 함께 nextCursorcursor로 돌려보내세요.

emails.iterate와 emails.listAll

iterate-emails.ts
for await (const email of openemail.emails.iterate({ status: 'failed' })) {  console.error(email.id, email.lastError)} const failures = await openemail.emails.listAll({ status: 'failed', from: '[email protected]' })

둘 다 nextCursor를 대신 따라갑니다. iterate는 반복문이 해당 페이지에 도달할 때에만 가져오므로 루프를 벗어나면 요청도 멈추고, listAll은 하나의 배열로 resolve되기 전에 모든 페이지를 훑으므로 끝이 있는 필터를 주어야 합니다. 어느 쪽이든 키셋 페이징이므로, 반복 중에 도착한 메시지가 오프셋 방식처럼 행을 건너뛰게 만들 수 없습니다.

emails.get과 emails.listEvents

get-email.ts
const email = await openemail.emails.get('msg_…')console.log(email.status, email.recipients) const events = await openemail.emails.listEvents('msg_…')for (const event of events) console.log(event.type, event.createdAt)

get은 주소마다 한 행씩 담긴 recipients를 반환하는 유일한 호출입니다. 50개의 메시지가 각각 수신자를 달고 오는 목록은 아무도 원하지 않는 보고서 한 페이지입니다.

매개변수

statusEmailStatus | EmailStatus[]
상태 하나 또는 여럿(`queued`, `scheduled`, `sending`, `sent`, `partial`, `cancelled`, `failed`)이며, 주어진 것 중 아무거나 일치하면 됩니다. 서버가 쉼표로 나누므로 SDK는 배열을 쉼표로 이어 붙인 하나의 값으로 보냅니다. 그 집합을 벗어난 값은 알 수 없는 값을 지목하는 422입니다.
fromstring
기록된 그대로의 발신 주소에 대한 정확한 일치이며, 그 값은 소문자로 된 `addr@host`입니다. 행은 표시 이름이 제거된 채로 기록되므로 `Acme <[email protected]>` 같은 꺾쇠 주소는 아무것도 일치시키지 못합니다. 전달한 값은 비교 전에 소문자로 바뀌며, 접두사나 도메인 일치가 아니라 동등 비교입니다.
limitnumber
이 페이지의 행 수이며 1에서 100까지, 기본값은 25입니다. 범위를 벗어난 값은 잘려 들어가지 않고 422로 거부됩니다.
cursorstring
페이징 기준이 될 메시지 id(`msg_…`)입니다. 오프셋이 아니라 키셋이므로 그 메시지의 `createdAt`보다 엄격히 오래된 행이 돌아오고, 페이지 중간에 도착한 발송이 행을 밀어낼 수 없습니다. 이 워크스페이스에 없는 메시지를 가리키는 id는 400입니다.

응답: Page<EmailResource>

itemsEmailResource[]
`createdAt` 기준 최신순으로 정렬된 메시지 한 페이지이며, API의 `data` 봉투에서 꺼낸 값입니다. 목록 행에는 주소별 `recipients` 내역이 담기지 않습니다. 그것은 `get`에 있습니다.
hasMoreboolean
이 페이지 너머에 필터와 일치하는 행이 더 있는지 여부입니다. 별도의 count 쿼리가 아니라 `limit`보다 한 행을 더 가져와서 판단합니다.
nextCursorstring | null
`cursor`로 돌려보낼 id이며, 마지막 페이지에서는 null입니다. `iterate`와 `listAll`은 이 값이 null이거나 `hasMore`가 false이면 멈춥니다. 커서를 주지 않으면서 더 있다고 주장하는 페이지는 영원히 반복될 테니까요.
items[].object'email'
이 목록의 행에서는 항상 `'email'`입니다.
items[].idstring
이 API 자체의 id인 `msg_…`입니다. 다른 모든 emails 엔드포인트가 받는 값이자 커서가 가리키는 값입니다.
items[].statusEmailStatus
메시지가 생애의 어느 지점에 있는지입니다. `partial`은 failed의 변종이 아니라 그 자체로 하나의 상태입니다. 일부 수신자는 이미 메시지를 받았고 되돌릴 수 없으므로 재시도는 잘못된 대응입니다.
items[].modeApiKeyMode
보낸 키에서 가져온 `live` 또는 `test`입니다. 테스트 발송은 여기에 기록되며 결코 전송되지 않습니다.
items[].fromstring
발송이 인가된 주소이며, 소문자로 주소만 저장됩니다. 따라서 `from`에 준 표시 이름은 실제 전송에는 나가지만 여기에는 보관되지 않습니다. 객체가 아니라 평범한 문자열인 이유는 이것이 인가된 신원이기 때문입니다. 키의 발송 범위를 벗어난 주소, 즉 키가 보유한 도메인에 속하지도 않고 키에 지정되지도 않은 주소는 403으로 거부되며, 사용할 수 있는 주소로 조용히 바뀌는 일은 결코 없습니다.
items[].subjectstring | null
저장된 그대로의 제목입니다. 제목 없이 기록된 메시지에서는 null입니다.
items[].messageIdstring | null
우리 id가 아니라 RFC 5322의 Message-ID입니다. MIME이 만들어지기 전까지는 null이고 발송 서비스가 나가는 길에 다시 씁니다. 따라서 이후의 반송이나 DSN은 다른 id를 담으며, 대조는 `items[].id`로 합니다.
items[].threadIdstring | null
이 메시지가 속한 스레드이며, 주어졌거나 배정된 경우에 한합니다. 그 외에는 null입니다.
items[].transportEmailTransport | (string & {}) | null
바이트가 어떤 경로로 나갔는지입니다. 발송 전에는 null이며, 이 SDK가 아직 이름을 알지 못하는 전송 수단이 호환성을 깨지 않도록 타입이 열려 있습니다. 저장된 기록에는 더 이상 쓰이지 않는 이름이 담겨 있을 수도 있습니다.
items[].attemptsnumber
이 메시지에 대한 발송 시도 횟수이며, 첫 시도 전에는 0입니다.
items[].lastErrorstring | null
가장 최근의 발송 오류로, 사람이 읽도록 쓰여 있습니다. 실패한 것이 없으면 null입니다.
items[].scheduledAtstring | null
메시지가 나갈 예정 시각이며 ISO-8601 시각입니다. 취소 시간이 없는 즉시 발송에서만 null입니다. 취소 시간은 짧은 지연일 뿐이므로 `cancellableForSeconds`도 이 값을 채우며, 그 행의 `status`는 `scheduled`가 아니라 `queued`입니다.
items[].cancellableUntilstring | null
메시지가 나갈 예정 시각으로, 지연된 발송에서는 `scheduledAt`과 같은 값을 담고 지연되지 않은 발송에서는 null입니다. 서버가 실제로 하는 검사가 아니라 화면에 표시할 시각입니다. `cancel`은 `status`로 분기하며, 메시지가 아직 `queued`나 `scheduled`일 때만 중단합니다.
items[].sentAtstring | null
실제로 나간 시각입니다. 발송이 완료되기 전까지는 null이며, 그래서 분기해야 할 필드는 이것이 아니라 `status`입니다.
items[].tagsRecord<string, string>
발송 시 제공한 레이블을 그대로 되돌려 주며 해석하지 않습니다. 항상 객체이고(설정한 것이 없으면 `{}`이며 null이 아닙니다) 되돌려 줄 뿐입니다. 이 엔드포인트는 `status`와 `from`으로 필터링하므로, 태그는 메시지를 찾는 수단이 아니라 메시지에서 읽어 내는 값입니다.
items[].sourceEmailSource
어떤 표면이 발송을 요청했는지입니다. `composer`, `api`, `mcp`, `ai`, `queue` 중 하나이며, `api`가 이 클라이언트입니다.
items[].createdAtstring
발송 기록이 쓰인 시각이며, 이는 실제 발송보다 앞섭니다. 이 목록이 정렬하는 필드이자 커서가 비교하는 필드입니다.
items[].trackingEmailTrackingSummary
참여 지표 요약이며, 추적된 메시지의 행에만 있고 그 외에는 없습니다. "이 메시지가 추적되었는가"에 대한 답이 바로 그 없음이며, `openCount: 0`은 "아무도 열지 않았다"로 읽힐 것입니다.
items[].tracking.opensboolean
이 메시지가 픽셀과 함께 나갔는지 여부입니다. 계정 설정이 지금 무엇인지가 아니라, 이 메시지에 적용된 값입니다.
items[].tracking.clicksboolean
이 메시지의 링크가 재작성되었는지 여부입니다. 본문에 재작성할 링크가 없었다면 false인데, 그때는 바뀐 것이 없기 때문입니다.
items[].tracking.openedboolean
집계된 열람이 하나라도 기록되었는지 여부이며, `openCount > 0`에서 파생됩니다.
items[].tracking.clickedboolean
집계된 클릭이 하나라도 기록되었는지 여부이며, `clickCount > 0`에서 파생됩니다.
items[].tracking.openCountnumber
사람이 발생시킨 것으로 보이는 열람을 메시지의 모든 사본에 대해 합한 값입니다. 스캐너와 프라이버시 프록시는 기록되지만 제외되며, 30초 이내의 반복 요청은 하나로 합쳐집니다.
items[].tracking.clickCountnumber
사본 전체에 대해 합한 집계 클릭 수입니다. 메시지 단위가 아니라 링크 단위로 중복 제거되는데, 몇 초 간격으로 두 링크를 따라간 것은 반복이 아니라 두 번의 행위이기 때문입니다.
items[].tracking.firstOpenAtstring | null
사본 전체에서 가장 이른 집계 열람이며, 없으면 null입니다. 기계에 의한 요청은 이 값을 움직이지 않습니다.
items[].translationEmailTranslationResource
목록 행에는 결코 없습니다. 번역 기록은 저장된 요청 안에 있고, 목록은 의도적으로 그것을 가져오지 않습니다. 여기에 없다는 사실은 메시지가 번역되었는지에 대해 아무것도 말해 주지 않습니다. `get`에 물어보세요.