エラー
すべての失敗は例外を送出する。クラスは 2 つで、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 | 両者の基底クラスであり、1 つの 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 の場合。キーがない、資格情報の種類が違う、あるいは当方が発行していないキーであることを意味する。 |
| 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 は str のままである。API はそれが開かれており追加のみが行われることを保証しているので、見覚えのない値は type として扱えばよい。閉じた Literal にしてしまうと、新しい失敗の種類を読むたびに SDK のアップグレードが必要になる。
API のエラーエンベロープではないボディも OpenEmailApiError になる。その場合 type はステータスから推定され、code には unrecognised_response が設定される。ボディが JSON でない成功レスポンスでも同じ例外が送出される。
AsyncOpenEmail の呼び出しをキャンセルしても、OpenEmailError は送出されない。リクエストの最中でも、リトライ前の待機中でも、キャンセルそのものが伝播し、その後に何かがリトライされることはない。
request_id
すべての OpenEmailApiError は、エラーボディまたは x-request-id ヘッダーからサーバーが返したリクエスト id を保持する。これは手元の失敗をサーバーのログの 1 行に結び付ける唯一の手がかりである。成功時に返されるのはパース済みのボディだけなので、そこから読み取れるリクエスト id はない。
str(error) の末尾にはステータス、コード、リクエスト id が付くので、例外を出力するログ行には 3 つすべてが残る。また OpenEmailApiError はすべてのフィールドを保ったまま pickle できるので、ワーカープロセスで送出されたものも親プロセスにそのまま届く。