이메일 API

조직이 인증한 도메인에서 이메일을 보냅니다. 발송 도메인은 콘솔에서 추가하고 인증합니다. 이 API는 해당 도메인으로 메시지를 보내고 각 메시지의 처리 결과를 알려줍니다.

호출 한 번에 수신자 한 명에게 보냅니다. to에는 주소 하나만 지정할 수 있고 cc와 bcc는 지원하지 않습니다. 여러 명에게 보내려면 수신자마다 이 엔드포인트를 한 번씩 호출하세요. 여러 주소를 한 메시지에 넣으면 주소 하나가 잘못됐을 때 전체 발송이 거부될 수 있기 때문입니다.

POST/organizations/:orgId/mails

하나의 메시지를 보냅니다. 런타임 범위 키 또는 Bearer 토큰이 필요합니다. html, text 또는 둘 다를 제공하세요.

요청 본문
{
  "from": "hello@yourdomain.com",
  "to": "customer@example.com",
  "subject": "Welcome aboard",
  "html": "<p>Thanks for signing up.</p>",
  "text": "Thanks for signing up.",
  "tag": "signup"              // Optional label of your own, returned as-is
}
응답 201
{
  "mail": {
    "id": "a1b2c3d4e5f6...",
    "from": "hello@yourdomain.com",
    "to": "cu******@example.com",
    "status": "sent",
    "tag": "signup",
    "deliveredAt": null,
    "openedAt": null,
    "error": null,
    "createdAt": "2026-08-06T...",
    "updatedAt": "2026-08-06T..."
  }
}

수신자 주소는 마스크 처리된 상태로 반환되고 그대로 저장됩니다. 따라서 로그가 유출되거나 키를 탈취당해도 고객 목록이 노출되지 않습니다. 전체 주소가 필요하면 직접 별도로 보관하세요.

from에 지정한 도메인은 인증된 도메인과 정확히 일치해야 합니다. 인증된 도메인의 서브도메인은 사용할 수 없습니다.

오류
400  Missing or malformed from, to, subject, or body, or a bad Idempotency-Key
403  That sending domain is not registered to this organization
409  Sending domain is not ready, or this Idempotency-Key was used with a different message
429  Send rate limit exceeded (5 messages/second). Wait retryAfter seconds
502  Upstream send failed; the message row is kept with status "failed"

429를 받으면 오류의 retryAfter에 표시된 초만큼 기다린 뒤 다시 보내세요. 즉시 반복해서 재시도하지 마세요. 제한은 조직별·초당 적용되며 반복 요청은 대기열만 길게 만듭니다.

중복 발송 없이 재시도하기

다음 Idempotency-Key 헤더에 최대 256자의 고유한 문자열을 넣으면 같은 요청을 재시도할 때 두 번째 메시지를 보내는 대신 기존 메시지를 반환합니다. 응답을 보기 전에 요청이 끝났더라도 이미 발송되었을 수 있습니다. 키 없이 반복하면 두 번 과금되고 두 번 전달되므로 이 헤더가 타임아웃 상황의 재시도를 안전하게 만듭니다.

동작
Same key, same message   200 with the original message (201 was the first send)
Same key, different message   409. Use a new key for each distinct message
Key is consumed even if the send failed. Retry that one with a new key
GET/organizations/:orgId/mails

조직이 보낸 메시지를 최신 순으로 조회합니다. 한 번에 받을 개수는 limit(1~100, 기본값 50)으로 정하고, 다음 페이지는 cursor로 요청하세요. 런타임 범위 키 또는 Bearer 토큰이 필요합니다.

응답
{
  "mails": [
    {
      "id": "a1b2c3d4e5f6...",
      "from": "hello@yourdomain.com",
      "to": "cu******@example.com",
      "status": "delivered",
      "tag": "signup",
      "deliveredAt": "2026-08-06T...",
      "openedAt": null,
      "error": null,
      "createdAt": "2026-08-06T...",
      "updatedAt": "2026-08-06T..."
    }
  ],
  "nextCursor": 41
}

다음 페이지를 가져올 때 nextCursor를 cursor로 보내세요. 마지막 페이지에서는 null입니다.

GET/organizations/:orgId/mails/:mailId

발송할 때 반환된 id로 하나의 메시지를 가져옵니다. 런타임 범위 키 또는 Bearer 토큰이 필요합니다.

상태 값
sent         Accepted for delivery. Every message starts here.
delivered    The receiving server accepted it. deliveredAt is set.
bounced      It could not be delivered. Stop sending to this address.
complained   The recipient marked it as spam. Stop sending to this address.
rejected     A virus was found in the message and it was not delivered.
failed       We could not hand it over at all. See error.

발송 결과가 반영되기까지 몇 초 걸릴 수 있습니다. 발송 직후에는 보통 아직 "sent"로 보이므로 상태를 주기적으로 다시 조회하거나 잠시 뒤 확인하세요.

openedAt은 수신자가 메시지를 열 때 설정됩니다. 정확한 측정치가 아닌 참고 정보로만 사용하세요. 많은 메일 클라이언트가 확인을 완전히 차단하고, 일부는 사람이 보지 않아도 미리 불러옵니다.

GET/organizations/:orgId/mails/guide

이메일 발송 가이드인 MAIL.md를 반환합니다. 조직의 발송 도메인과 현재 상태가 채워져 있습니다. 배포 범위 키 또는 Bearer 토큰이 필요하므로 런타임 키를 사용하면 403이 반환됩니다.

응답
{ "guide": "# Sending email with JustDeploy\n..." }

반송과 스팸 신고는 조직별로 집계되며 둘 중 하나라도 너무 높아지면 조직 전체의 발송이 중지됩니다.