> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.claw-ops.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.claw-ops.com/_mcp/server.

# 이메일 조회 (보낸 것·받은 것)

GET https://api.claw-ops.com/v1/accounts/{accountId}/emails

이 계정의 이메일을 최신순으로 조회합니다. **보낸 것과 받은 것이 같은 목록**에 나오며
`direction` 으로 구분합니다 — 통화·문자 조회와 같은 방식입니다.

한쪽만 보려면 `direction=outbound` 또는 `direction=inbound` 를 주십시오.

⚠️ 보낸 메일의 `status` 는 **공급자 접수 여부**입니다 — 수신함 도착이 아닙니다.
전달·반송은 비동기로 확인되며 이 값은 그 뒤에도 바뀌지 않습니다.

⚠️ 본문은 목록에 실리지 않습니다. 단건 조회로 받으십시오.

Reference: https://docs.claw-ops.com/api-reference/claw-ops-api/emails/list-emails

## Authentication

- `Authorization` header (bearer token, required) — API Key를 Bearer 토큰으로 전달

## Request

### Path parameters

- `accountId` (string, required) — 계정 ID

### Query parameters

- `direction` (enum, optional) — 방향 필터. **지정하지 않으면 양방향이 함께** 나옵니다.
  - Allowed values: `outbound`, `inbound`
- `status` (enum, optional) — 상태 필터. 받은 메일은 항상 `received` 입니다.
  - Allowed values: `sent`, `failed`, `received`
- `from` (string, optional) — 발신 주소 필터(정확히 일치). 특정 상대와 오간 메일을 찾을 때 씁니다.
- `recipient` (string, optional) — **받은 메일이 실제로 배달된 주소** 필터(정확히 일치). 한 도메인에 `support@`·`sales@` 처럼 여러 주소를 두고 처리를 나눈다면 이 필터를 쓰십시오. ⚠️ 숨은 참조(BCC)로 온 메일은 `to` 헤더에 주소가 없으므로 `to` 로는 찾을 수 없습니다.
- `receivedAfter` (datetime, optional) — 이 시각 **이상**(포함). `direction=inbound` 면 공급자가 받은 시각, 그 밖에는 생성 시각 기준입니다.
- `receivedBefore` (datetime, optional) — 이 시각 **미만**(제외).
- `emailDomainId` (string, optional) — 발신 도메인 필터. 검증한 도메인이 여럿일 때 씁니다.
- `page` (integer, optional, default: 0) — 페이지 번호(0-based)
- `pageSize` (integer, optional, default: 20) — 페이지 크기(최대 100)
- `page_size` (integer, optional, deprecated) — `pageSize` 의 별칭(하위호환). 신규 연동은 `pageSize` 를 사용하세요.
- `limit` (integer, optional, deprecated) — `pageSize` 의 별칭(하위호환). 신규 연동은 `pageSize` 를 사용하세요.

## Response

### 200

이메일 목록

- `data` (list of EmailResponse, required)
- `meta` (EmailListResponseMeta, required)

## Errors

### 400 Bad Request Error

`page`·`pageSize` 가 정수가 아님.

- `error` (string, optional) — 사람이 읽을 수 있는 에러 메시지
- `code` (string, optional) — 기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서 바뀔 수 있지만 코드는 계약입니다. 같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는 - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서 해제해야 발신됩니다. - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다. 전화번호 정규화 관련: - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님) - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)
- `ip` (string, optional) — `overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다. 해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔 「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.

### 401 Unauthorized Error

인증 실패

- `error` (string, optional) — 사람이 읽을 수 있는 에러 메시지
- `code` (string, optional) — 기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서 바뀔 수 있지만 코드는 계약입니다. 같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는 - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서 해제해야 발신됩니다. - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다. 전화번호 정규화 관련: - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님) - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)
- `ip` (string, optional) — `overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다. 해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔 「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.

### 403 Forbidden Error

접근 권한 없음

- `error` (string, optional) — 사람이 읽을 수 있는 에러 메시지
- `code` (string, optional) — 기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서 바뀔 수 있지만 코드는 계약입니다. 같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는 - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서 해제해야 발신됩니다. - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다. 전화번호 정규화 관련: - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님) - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)
- `ip` (string, optional) — `overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다. 해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔 「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.

## Types

### EmailResponse

이메일 한 건. **보낸 것과 받은 것이 같은 모양**이며 `direction` 으로 구분합니다 (통화·문자와 같은 규약입니다). 방향 전용 필드는 반대 방향에서 `null` 입니다 — 받은 메일에는 `failureCode` 가, 보낸 메일에는 `verdicts`·`recipients` 가 `null` 입니다. ⚠️ **스레드 필드(`replyTo`·`inReplyTo`·`references`)는 방향 전용이 아닙니다.** 답장으로 보낸 메일도 사슬을 가집니다. 예외는 `messageId` 하나이며, 보낸 메일에서 `null` 인 이유는 "해당 없음" 이 아니라 **공급자가 그 헤더를 덮어써서 우리도 모른다**는 것입니다.

- `emailId` (string, required) — ClawOps 이메일 리소스 ID.
- `direction` (enum, required) — `outbound` 는 이 계정이 보낸 메일, `inbound` 는 이 계정의 **수신 도메인으로 들어온** 메일입니다.
  - Allowed values: `outbound`, `inbound`
- `status` (enum, required) — 보낸 메일은 `sent`(공급자 접수) 또는 `failed` 입니다 — `sent` 는 **접수됐다**는 뜻이지 수신함 도착이 아닙니다. 받은 메일은 항상 `received` 입니다.
  - Allowed values: `sent`, `failed`, `received`
- `from` (string, required)
- `to` (list of string, required)
- `recipientCount` (integer, required) — 보낸 메일에서는 **과금 단위**입니다 — 실제로 발송한 To+Cc+Bcc 의 합계이며 한 통을 3명에게 보내면 3입니다. **수신거부로 빠진 주소는 세지 않습니다**(`suppressed` 참고). 받은 메일에서는 **이 계정에 실제로 배달된 주소 수**(`recipients` 의 길이)입니다.
- `createdAt` (datetime, required)
- `cc` (list of string, optional)
- `bcc` (list of string, optional)
- `suppressed` (list of string, optional) — 수신거부 명단에 있어 이 발송에서 **빠진** 주소들. 요청한 표기 그대로 돌려줍니다. ⚠️ 이메일은 차단된 수신자가 있어도 **나머지에게는 보냅니다**(전화·문자가 발신 전체를 거절하는 것과 다릅니다). 그래서 `201` 을 받고도 일부가 안 갔을 수 있고, **이 칸이 그걸 알려주는 유일한 자리**입니다. 비어 있으면 아무도 빠지지 않았다는 뜻입니다. `recipientCount` 에는 포함되지 않습니다 — 요청한 수신자 수는 `recipientCount + suppressed.length` 입니다. 받은 메일에서는 항상 빈 배열입니다.
- `subject` (string, optional, nullable)
- `attachmentCount` (integer, optional)
- `failureCode` (string, optional, nullable) — 실패 사유 코드. `status` 가 `sent` 면 `null` 입니다. `provider_unavailable` 은 **공급자를 부르지 못한** 경우이고, 그 밖의 값은 공급자가 거절한 경우입니다.
- `failureMessage` (string, optional, nullable) — 사람이 읽는 실패 설명. `status` 가 `sent` 면 `null` 입니다.
- `replyTo` (list of string, optional) — 답장 주소(`Reply-To`). 받은 메일은 발신자가 지정한 주소, 보낸 메일은 발송할 때 지정한 값입니다. ⭐ **답장은 `from` 이 아니라 이 주소로 보내십시오.** 비어 있을 때만 `from` 이 답장 주소입니다(RFC 5322 §3.6.2). 뉴스레터·티켓 시스템은 대부분 이 값을 다르게 둡니다.
- `messageId` (string, optional, nullable) — 이 메일 자신의 `Message-ID`(꺾쇠 `< >` 제외). **답장할 때 `inReplyTo` 에 그대로 넣는 값입니다.** ⛔ **보낸 메일은 항상 `null`** 입니다. 이 헤더는 공급자가 발급하며 우리가 지정한 값을 덮어쓰기 때문에 우리도 그 값을 모릅니다. ⚠️ 받은 메일도 `null` 일 수 있습니다 — 이 헤더는 RFC 상 필수가 아니고, 붙이지 않고 보내는 발신자가 실제로 있습니다. 그 메일에는 스레드로 답장할 수 없습니다.
- `inReplyTo` (string, optional, nullable) — 이 메일이 답장한 원본의 `Message-ID`(꺾쇠 제외). 답장이 아니면 `null` 입니다.
- `references` (list of string, optional) — 대화의 조상 사슬. **오래된 것이 앞**입니다. 다음 답장에 넘길 값은 `[...references, messageId]` 입니다. ⚠️ 보낸 메일의 값은 요청하신 목록이 아니라 **실제로 헤더에 실어 보낸 목록**입니다. 긴 대화는 공급자 헤더 길이 상한 때문에 RFC 5537 §3.4.4 에 따라 첫 항목과 최근 항목만 남기고 줄여 보냅니다.
- `recipients` (list of string, optional, nullable) — **실제로 이 계정에 배달된 주소.** 받은 메일에만 있습니다(보낸 메일은 `null`). ⚠️ **`to` 를 보고 라우팅하지 마십시오.** 숨은 참조(BCC)로 온 메일은 `to` 에 그 주소가 **없습니다** — 이 필드에만 있습니다. 한 도메인에 `support@`·`sales@` 처럼 여러 주소를 두고 처리를 나눈다면 반드시 이 값을 쓰십시오.
- `receivedAt` (datetime, optional, nullable) — 공급자가 메일을 받은 시각. 받은 메일에만 있습니다.
- `sizeBytes` (integer, optional, nullable) — 받은 메일의 원문 크기(바이트). ⚠️ 공급자가 덧붙인 헤더(약 3.6KB)가 포함된 값이라 메일 클라이언트가 보여 주는 크기와 다를 수 있습니다. **과금은 이 값 기준입니다.**
- `verdicts` (EmailResponseVerdicts, optional, nullable) — 공급자의 스팸·바이러스·인증 판정. 받은 메일에만 있습니다. ⚠️ **값은 공급자 원문 그대로**입니다(`PASS`·`FAIL`·`GRAY`·`PROCESSING_FAILED` 등). 우리가 해석하지 않으므로 목록이 늘어날 수 있습니다 — 모르는 값을 만나면 안전한 쪽으로 처리하십시오. ⛔ **`from` 만 믿고 자동 처리하지 마십시오.** 발신자는 위조될 수 있고, 그걸 판별하라고 `spf`·`dkim`·`dmarc` 를 함께 드립니다.
- `parseStatus` (enum, optional, nullable) — 받은 메일의 본문 해석 결과. `unparsable` 이면 본문을 읽지 못한 것이며, 그때도 원문은 그대로 보관되어 단건 조회의 `raw` 로 받을 수 있습니다.
  - Allowed values: `parsed`, `unparsable`

### EmailListResponseMeta

- `page` (integer, required) — 0-based 페이지 번호.
- `pageSize` (integer, required)
- `total` (integer, required) — 필터를 적용한 전체 건수.

### EmailResponseVerdicts

공급자의 스팸·바이러스·인증 판정. 받은 메일에만 있습니다. ⚠️ **값은 공급자 원문 그대로**입니다(`PASS`·`FAIL`·`GRAY`·`PROCESSING_FAILED` 등). 우리가 해석하지 않으므로 목록이 늘어날 수 있습니다 — 모르는 값을 만나면 안전한 쪽으로 처리하십시오. ⛔ **`from` 만 믿고 자동 처리하지 마십시오.** 발신자는 위조될 수 있고, 그걸 판별하라고 `spf`·`dkim`·`dmarc` 를 함께 드립니다.

- `spam` (string, optional, nullable)
- `virus` (string, optional, nullable)
- `spf` (string, optional, nullable)
- `dkim` (string, optional, nullable)
- `dmarc` (string, optional, nullable)

## Examples

**Response**

```json
{
  "data": [
    {
      "emailId": "clx9eml00001",
      "direction": "inbound",
      "status": "sent",
      "from": "no-reply@example.com",
      "to": [
        "customer@gmail.com"
      ],
      "recipientCount": 1,
      "createdAt": "2026-09-03T07:20:00.000Z",
      "cc": [],
      "bcc": [],
      "suppressed": [],
      "subject": "주문이 접수되었습니다",
      "attachmentCount": 1,
      "failureCode": null,
      "failureMessage": null,
      "replyTo": [
        "support@example.com"
      ],
      "messageId": "CAF7n8xW1p_abc@mail.gmail.com",
      "inReplyTo": null,
      "references": [
        "CAF7n8xW1p_xyz@mail.gmail.com",
        "CAF7n8xW1p_abc@mail.gmail.com"
      ],
      "recipients": [
        "support@example.com"
      ],
      "receivedAt": "2026-09-04T05:48:00.000Z",
      "sizeBytes": 4030,
      "verdicts": {
        "spam": "PASS",
        "virus": "PASS",
        "spf": "PASS",
        "dkim": "PASS",
        "dmarc": "GRAY"
      },
      "parseStatus": "parsed"
    }
  ],
  "meta": {
    "page": 0,
    "pageSize": 20,
    "total": 137
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails"

querystring = {"direction":"inbound","emailDomainId":"clx9dom00001","from":"customer@gmail.com","limit":"100","page":"0","pageSize":"20","page_size":"50","receivedAfter":"2026-09-01T00:00:00Z","receivedBefore":"2026-10-01T00:00:00Z","recipient":"support@example.com","status":"failed"}

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/emails?direction=inbound&emailDomainId=clx9dom00001&from=customer%40gmail.com&limit=100&page=0&pageSize=20&page_size=50&receivedAfter=2026-09-01T00%3A00%3A00Z&receivedBefore=2026-10-01T00%3A00%3A00Z&recipient=support%40example.com&status=failed")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```