Python
목록과 단건 조회
`emails.list`, `emails.list_all`, `emails.iterate`, `emails.get`, `emails.list_events`.
emails.list
from openemail import openemail first = openemail.emails.list(status=['queued', 'scheduled'], from_='[email protected]', limit=50) if first['nextCursor']: second = openemail.emails.list( status=['queued', 'scheduled'], from_='[email protected]', limit=50, cursor=first['nextCursor'], )페이지는 {'items': [...], 'hasMore': ..., 'nextCursor': ...}입니다. 그다음 페이지를 받으려면 같은 필터와 함께 nextCursor를 cursor로 돌려보내세요.
emails.iterate와 emails.list_all
import sys from openemail import openemail for email in openemail.emails.iterate(status='failed'): print(email['id'], email['lastError'], file=sys.stderr) failures = openemail.emails.list_all(status='failed', from_='[email protected]')둘 다 nextCursor를 대신 따라갑니다. iterate는 루프가 해당 페이지에 도달할 때에만 가져오는 제너레이터이므로 루프를 벗어나면 요청도 멈추고, list_all은 하나의 리스트를 반환하기 전에 모든 페이지를 훑으므로 끝이 있는 필터를 주어야 합니다. 어느 쪽이든 키셋 페이징이므로, 반복 중에 도착한 메시지가 오프셋 방식처럼 행을 건너뛰게 만들 수 없습니다.
emails.get과 emails.list_events
from openemail import openemail email = openemail.emails.get('msg_…')print(email['status'], email['recipients']) events = openemail.emails.list_all_events('msg_…')for event in events: print(event['type'], event['createdAt'])get은 주소마다 한 행씩 담긴 recipients를 반환하는 유일한 호출입니다. 50개의 메시지가 각각 수신자를 달고 오는 목록은 아무도 원하지 않는 보고서 한 페이지입니다.
매개변수
statusEmailStatus | Sequence[EmailStatus]- 상태 하나 또는 여럿(`queued`, `scheduled`, `sending`, `sent`, `partial`, `bounced`, `cancelled`, `failed`)이며, 주어진 것 중 아무거나 일치하면 됩니다. 서버가 쉼표로 나누므로 SDK는 리스트를 쉼표로 이어 붙인 하나의 값으로 보냅니다. 그 집합을 벗어난 값은 알 수 없는 값을 지목하는 422입니다.
broadcast_idstr- 브로드캐스트 하나의 사본만이며, `broadcasts.send`에서 받은 `brd_` ID를 씁니다. 브로드캐스트가 닿은 사람은 모두 자기 메시지를 받으므로, 이것으로 누구에게 갔고 각 사본이 어떻게 되었는지 나열합니다. `broadcasts.list_recipients`는 같은 사람들을 열람, 클릭, 수신 거부와 함께 나열합니다.
from_str- 기록된 그대로의 발신 주소에 대한 정확한 일치이며, 그 값은 소문자로 된 `addr@host`입니다. 행은 표시 이름이 제거된 채로 기록되므로 `Acme <[email protected]>` 같은 꺾쇠 주소는 아무것도 일치시키지 못합니다. 전달한 값은 비교 전에 소문자로 바뀌며, 접두사나 도메인 일치가 아니라 동등 비교입니다. 끝의 밑줄은 `from`이 Python 예약어이기 때문에 붙어 있습니다.
limitint- 이 페이지의 행 수이며 1에서 100까지, 기본값은 25입니다. 범위를 벗어난 값은 잘려 들어가지 않고 422로 거부됩니다.
cursorstr- 페이징 기준이 될 메시지 id(`msg_…`)입니다. 오프셋이 아니라 키셋이므로 그 메시지의 `createdAt`보다 엄격히 오래된 행이 돌아오고, 페이지 중간에 도착한 발송이 행을 밀어낼 수 없습니다. 이 워크스페이스에 없는 메시지를 가리키는 id는 400입니다.
scheduled_fromdatetime | str- 이 시각 또는 그 이후로 예약된 메시지만입니다. `datetime`이나 시간대가 포함된 ISO-8601 시각으로 지정합니다. `scheduledAt`이 없는 메시지는 제외되므로, `scheduled_to`와 `status=['queued', 'scheduled']`를 함께 쓰면 특정 기간에 나갈 예정인 메시지를 나열할 수 있습니다.
scheduled_todatetime | str- 이 시각 또는 그 이전으로 예약된 메시지만입니다. 이보다 늦은 `scheduled_from`을 주면 `scheduledTo`에 대한 422 `invalid_parameter`가 됩니다.
응답: Page[EmailResource]
itemslist[EmailResource]- `createdAt` 기준 최신순으로 정렬된 메시지 한 페이지이며, API의 `data` 봉투에서 꺼낸 값입니다. 목록 행에는 주소별 `recipients` 내역이 담기지 않습니다. 그것은 `get`에 있습니다.
hasMorebool- 이 페이지 너머에 필터와 일치하는 행이 더 있는지 여부입니다. 별도의 count 쿼리가 아니라 `limit`보다 한 행을 더 가져와서 판단합니다.
nextCursorstr | None- `cursor`로 돌려보낼 id이며, 마지막 페이지에서는 null입니다. `iterate`와 `list_all`은 이 값이 null이거나 `hasMore`가 false이면 멈춥니다. 커서를 주지 않으면서 더 있다고 주장하는 페이지는 영원히 반복될 테니까요.
items[].objectLiteral['email']- 이 목록의 행에서는 항상 `'email'`입니다.
items[].idstr- 이 API 자체의 id인 `msg_…`입니다. 다른 모든 emails 엔드포인트가 받는 값이자 커서가 가리키는 값입니다.
items[].statusEmailStatus- 메시지가 생애의 어느 지점에 있는지입니다. `partial`은 failed의 변종이 아니라 그 자체로 하나의 상태입니다. 일부 수신자는 이미 메시지를 받았고 되돌릴 수 없으므로 재시도는 잘못된 대응입니다. `bounced`는 보낸 뒤 모든 수신자에게서 반송되어 아무도 받지 못했다는 뜻이며, `get`의 각 수신자에 그 이유가 나옵니다.
items[].modeApiKeyMode- 보낸 키에서 가져온 `live` 또는 `test`입니다. 테스트 발송은 여기에 기록되며 결코 전송되지 않습니다.
items[].fromstr- 발송이 인가된 주소이며, 소문자로 주소만 저장됩니다. 따라서 `from`에 준 표시 이름은 실제 전송에는 나가지만 여기에는 보관되지 않습니다. dict가 아니라 평범한 문자열인 이유는 이것이 인가된 신원이기 때문입니다. 키의 발송 범위를 벗어난 주소, 즉 키가 보유한 도메인에 속하지도 않고 키에 지정되지도 않은 주소는 403으로 거부되며, 사용할 수 있는 주소로 조용히 바뀌는 일은 결코 없습니다.
items[].subjectstr | None- 저장된 그대로의 제목입니다. 제목 없이 기록된 메시지에서는 null입니다.
items[].messageIdstr | None- 우리 id가 아니라 RFC 5322의 Message-ID입니다. MIME이 만들어지기 전까지는 null이고 발송 서비스가 나가는 길에 다시 씁니다. 따라서 이후의 반송이나 DSN은 다른 id를 담으며, 대조는 `items[].id`로 합니다.
items[].threadIdstr | None- 이 메시지가 속한 스레드이며, 주어졌거나 배정된 경우에 한합니다. 그 외에는 null입니다.
items[].transportEmailTransport | str | None- 바이트가 어떤 경로로 나갔는지입니다. 발송 전에는 null이며, 이 SDK가 아직 이름을 알지 못하는 전송 수단이 호환성을 깨지 않도록 타입이 열려 있습니다. 저장된 기록에는 더 이상 쓰이지 않는 이름이 담겨 있을 수도 있습니다.
items[].attemptsint- 이 메시지에 대한 발송 시도 횟수이며, 첫 시도 전에는 0입니다.
items[].lastErrorstr | None- 가장 최근의 발송 오류로, 사람이 읽도록 쓰여 있습니다. 실패한 것이 없으면 null입니다.
items[].scheduledAtstr | None- 메시지가 나갈 예정 시각이며 ISO-8601 시각입니다. 취소 시간이 없는 즉시 발송에서만 null입니다. 취소 시간은 짧은 지연일 뿐이므로 `cancellableForSeconds`도 이 값을 채우며, 그 행의 `status`는 `scheduled`가 아니라 `queued`입니다.
items[].cancellableUntilstr | None- 메시지가 나갈 예정 시각으로, 지연된 발송에서는 `scheduledAt`과 같은 값을 담고 지연되지 않은 발송에서는 null입니다. 서버가 실제로 하는 검사가 아니라 화면에 표시할 시각입니다. `cancel`은 `status`로 분기하며, 메시지가 아직 `queued`나 `scheduled`일 때만 중단합니다.
items[].sentAtstr | None- 실제로 나간 시각입니다. 발송이 완료되기 전까지는 null이며, 그래서 분기해야 할 필드는 이것이 아니라 `status`입니다.
items[].tagsdict[str, str]- 발송할 때 준 라벨로, 그대로 돌려주며 해석하지 않습니다. 항상 dict이고(아무것도 설정하지 않으면 `{}`, null은 아님) 돌려주기만 합니다. 이 호출은 `status`, `from_`, `broadcast_id`, `scheduled_from`, `scheduled_to`로 필터링하므로, 태그는 메시지에서 읽는 것이지 메시지를 찾는 방법이 아닙니다.
items[].broadcastIdstr | None- 이 메시지가 사본인 `brd_` 브로드캐스트, 또는 단독으로 보낸 메시지라면 null.
items[].sourceEmailSource | str- 어떤 표면이 발송을 요청했는지입니다. `composer`, `api`, `mcp`, `ai`, `oauth`, `form` 중 하나이며, API 키를 쓰는 이 클라이언트는 `api`, 액세스 토큰을 쓰는 이 클라이언트는 `oauth`입니다.
items[].createdAtstr- 발송 기록이 쓰인 시각이며, 이는 실제 발송보다 앞섭니다. 이 목록이 정렬하는 필드이자 커서가 비교하는 필드입니다.
items[].trackingNotRequired[EmailTrackingSummary]- 참여 지표 요약이며, 추적된 메시지의 행에만 있고 그 외에는 없습니다. "이 메시지가 추적되었는가"에 대한 답이 바로 그 없음이며, `openCount: 0`은 "아무도 열지 않았다"로 읽힐 것입니다.
items[].tracking.opensbool- 이 메시지가 픽셀과 함께 나갔는지 여부입니다. 계정 설정이 지금 무엇인지가 아니라, 이 메시지에 적용된 값입니다.
items[].tracking.clicksbool- 이 메시지의 링크가 재작성되었는지 여부입니다. 본문에 재작성할 링크가 없었다면 false인데, 그때는 바뀐 것이 없기 때문입니다.
items[].tracking.openedbool- 집계된 열람이 하나라도 기록되었는지 여부이며, `openCount > 0`에서 파생됩니다.
items[].tracking.clickedbool- 집계된 클릭이 하나라도 기록되었는지 여부이며, `clickCount > 0`에서 파생됩니다.
items[].tracking.openCountint- 사람이 발생시킨 것으로 보이는 열람을 메시지의 모든 사본에 대해 합한 값입니다. 스캐너와 프라이버시 프록시는 기록되지만 제외되며, 30초 이내의 반복 요청은 하나로 합쳐집니다.
items[].tracking.clickCountint- 사본 전체에 대해 합한 집계 클릭 수입니다. 메시지 단위가 아니라 링크 단위로 중복 제거되는데, 몇 초 간격으로 두 링크를 따라간 것은 반복이 아니라 두 번의 행위이기 때문입니다.
items[].tracking.firstOpenAtstr | None- 사본 전체에서 가장 이른 집계 열람이며, 없으면 null입니다. 기계에 의한 요청은 이 값을 움직이지 않습니다.
items[].translationNotRequired[EmailTranslationResource]- 목록 행에는 결코 없습니다. 번역 기록은 저장된 요청 안에 있고, 목록은 의도적으로 그것을 가져오지 않습니다. 여기에 없다는 사실은 메시지가 번역되었는지에 대해 아무것도 말해 주지 않습니다. `get`에 물어보세요.