오류
모든 실패는 예외를 발생시킵니다. 클래스는 두 가지이며, 모든 API 오류에는 요청 id가 담깁니다.
오류 잡기
from openemail import OpenEmailApiError, OpenEmailNetworkError, openemail try: openemail.emails.send({'from': sender, 'to': recipient, 'subject': subject, 'text': text})except OpenEmailApiError as error: if error.is_validation: print(error.code, error.param, error.message) if error.is_permission: print(openemail.addresses.list()) if error.is_rate_limited: print('try again in', error.retry_after_seconds, 'seconds') print(error.status, error.request_id) raiseexcept OpenEmailNetworkError as error: if error.is_timeout: print('no answer in time') raise발송에서 나는 permission_error는 대개 워크스페이스가 아니라 키 자체의 발송 범위, 즉 키에 부여되지 않은 도메인이나 주소 때문입니다. 예제가 이 키로 어떤 주소에서 보낼 수 있는지를 addresses.list()로 확인해 출력하는 이유가 여기에 있습니다.
클래스
| 클래스 | 발생 조건 |
|---|---|
| OpenEmailApiError | API가 응답했지만 성공이 아니었습니다. message, status, type, code, param, doc_url, request_id, retry_after_seconds, fields, body를 담고 있습니다. |
| OpenEmailNetworkError | 응답이 전혀 오지 않았습니다. DNS, TLS, 끊긴 연결, 타임아웃 때문입니다. 그 밑에 있는 httpx 예외를 cause에 담으며, 타임아웃이 원인이면 is_timeout이 True입니다. |
| OpenEmailError | 둘의 기반 클래스이므로, except 하나로 API나 네트워크 때문에 생긴 모든 실패를 잡을 수 있습니다. verify_webhook_signature가 발생시키는 WebhookVerificationError도 이 클래스를 상속합니다. |
| ValueError | 아무것도 전송되기 전에 발생합니다. 키가 없거나 형식이 잘못된 경우, 사용할 수 없는 base_url, 암호화되지 않은 http로 보내질 자격 증명, 빈 id가 여기에 해당합니다. 잘못된 http_client나 JSON으로 담을 수 없는 본문은 대신 TypeError를 발생시킵니다. |
fields는 가입 양식이 거부한 각 답변을 key와 error로 나열하며, 그 밖의 모든 오류에서는 None입니다. body는 API가 보낸 JSON을 담고 있으며, 본문이 JSON이 아니었다면 None입니다.
| 속성 | true가 되는 조건 |
|---|---|
| is_auth | type이 authentication_error인 401입니다. 키가 없거나, 자격 증명의 종류가 잘못되었거나, OpenEmail이 발급하지 않은 키입니다. |
| is_permission | permission_error, 즉 403입니다. 유효한 키이지만 필요한 스코프나 From 주소를 갖고 있지 않습니다. |
| is_scope_missing | code가 insufficient_scope인 경우로, 빠진 스코프를 명시하는 403입니다. |
| is_invalid_request | invalid_request_error, 즉 400입니다. 해석할 수 없는 요청입니다. 크기 상한을 넘은 메시지는 422 message_too_large로 돌아오므로, 그 경우를 잡는 속성은 is_validation입니다. |
| is_validation | validation_error, 즉 422입니다. 스키마가 요청을 거부했으며 param이 해당 필드를 가리킵니다. |
| is_not_found | not_found_error, 즉 404입니다. 그런 리소스가 없습니다. |
| is_conflict | conflict_error, 즉 409입니다. 리소스가 이미 이 작업을 할 수 있는 시점을 지났습니다. |
| is_rate_limited | rate_limit_error, 즉 429입니다. 서버가 대기 시간을 지정한 경우 retry_after_seconds에 그 값이 담깁니다. |
| is_server_error | status가 500 이상입니다. 지원팀에 문의할 때는 request_id를 함께 알려 주십시오. |
| is_retryable | status가 408, 429, 500, 502, 503, 504 중 하나입니다. |
| is_step_up_required | code가 step_up_required인 경우로, 사용자가 코드를 인증하기 전까지 OAuth 액세스 토큰이 민감한 변경 전에 받는 403입니다. |
대부분의 속성은 오류 봉투에서 고정된 쪽인 type을 읽습니다. code는 API가 개방적이고 추가만 된다고 보장하는 값이므로 str로 남아 있으며, 알아보지 못하는 값은 그 type으로 취급하십시오. 닫힌 Literal로 만들면 새로운 실패 모드를 읽는 대가로 SDK를 업그레이드해야 합니다.
API의 오류 봉투 형식이 아닌 본문도 여전히 OpenEmailApiError가 되며, type은 상태 코드에서 추론하고 code는 unrecognised_response로 설정됩니다. 본문이 JSON이 아닌 성공 응답도 마찬가지로 이 예외를 발생시킵니다.
AsyncOpenEmail 호출을 취소해도 OpenEmailError는 발생하지 않습니다. 요청 도중이든 재시도 전 대기 중이든 취소 자체가 그대로 전파되며, 그 뒤에는 아무것도 재시도되지 않습니다.
request_id
모든 OpenEmailApiError는 서버가 보낸 요청 id를 오류 본문이나 x-request-id 헤더에서 가져와 담고 있으며, 이 값만이 여러분의 실패를 서버 로그의 한 줄과 이어 줍니다. 성공하면 파싱된 본문만 반환되므로 거기서 읽을 요청 id는 없습니다.
str(error)는 상태 코드, 오류 코드, 요청 id로 끝나므로, 예외를 출력하는 로그 줄에는 세 가지가 모두 남습니다. OpenEmailApiError는 모든 필드를 유지한 채 pickle할 수 있어서, 워커 프로세스에서 발생한 예외도 부모 프로세스에 온전히 전달됩니다.