신규 고객모든 신규 계정에 DNS와 CDN 무료 요금제를 제공합니다.계정 만들기

SMTP 및 HTTP API

API 키를 생성하고 SMTP 또는 HTTP API로 메일을 보냅니다. 요청 필드, 응답, 오류 코드, 예제를 포함합니다.

8 분 소요 업데이트 2026년 10월 20일

스트림을 통해 발송하는 방법은 두 가지입니다. 모든 애플리케이션이나 메일 라이브러리에서 SMTP로 보내거나 HTTP API를 사용합니다. 두 방법 모두 같은 API 키, 할당량, 억제 목록, 이벤트를 사용합니다. 시작하기 전에 발신 도메인을 인증하고 API 키를 생성하십시오.

API 키

  1. 스트림을 열고 API 키 탭으로 이동합니다.
  2. 키 생성을 클릭하고 production과 같은 이름을 입력한 뒤 확인합니다.
  3. 표시된 키를 복사하고 저장했습니다를 클릭합니다. 키는 이때 한 번만 표시됩니다. 이후 목록에는 ytm_aB3dE6gH…와 같은 접두사만 표시됩니다.

모든 키는 ytm_로 시작합니다. 스트림당 최대 20개의 활성 키를 가질 수 있습니다. 목록에는 각 키를 마지막으로 사용한 시각이 표시됩니다. 키를 더 이상 사용하지 않으려면 폐기를 클릭합니다. 해당 키를 사용하는 프로그램은 즉시 작동을 멈춥니다. 키는 해당 키가 속한 스트림에서만 작동합니다.

경고

API 키는 서버에만 보관하십시오. 브라우저 코드, 모바일 앱, 공개 저장소에 넣지 마십시오. 키를 가진 사람은 누구나 고객의 도메인으로 메일을 보낼 수 있습니다.

SMTP

스트림의 개요 탭에 SMTP 설정이 표시됩니다.

설정값
호스트스트림에 표시된 SMTP 호스트, 보통 smtp.tm.yeapcloud.net
포트STARTTLS 사용 시 587, TLS 사용 시 465
사용자 이름apikey(이 단어 그대로)
비밀번호이 스트림의 API 키
카테고리 헤더X-Yeap-Category

콘솔에 표시된 호스트를 사용하십시오. 일부 스트림은 자체 호스트 이름을 가진 다른 서버 그룹을 통해 발송합니다.

SMTP 발송 방식:

  • From 헤더에는 스트림에서 인증된 도메인의 주소를 사용해야 합니다.
  • 각 수신자(To, Cc, Bcc)는 별도의 사본과 별도의 메시지 ID를 받으며, 각각 이메일 1통으로 계산됩니다.
  • 카테고리를 지정하려면 X-Yeap-Category: password-reset과 같은 헤더를 추가합니다. 이 헤더는 전달 전에 제거됩니다. 허용되는 문자는 영문자, 숫자, ., _, -이며 최대 64자입니다.
  • 메시지 크기는 최대 25 MB이며, SMTP 트랜잭션당 최대 1,000명의 수신자를 지정할 수 있습니다.
  • 모든 메시지에는 X-TM-ID 헤더(발송 기록과 이벤트에 나타나는 메시지 ID)와 메일함 제공업체의 피드백 루프용 Feedback-ID 헤더가 추가됩니다.
  • 마케팅 스트림에서는 직접 설정한 List-Unsubscribe 헤더가 Yeap Cloud의 원클릭 수신 거부 헤더로 대체됩니다. SMTP는 메시지 본문을 변경하지 않으므로 우편 주소와 수신 거부 링크를 직접 콘텐츠에 추가하십시오. 억제 목록 및 수신 거부를 참조하십시오.
  • 열람 및 클릭 추적은 HTTP API를 통해서만 사용할 수 있습니다.

Python 표준 라이브러리 예제:

python
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Example <noreply@example.com>"
msg["To"] = "user@example.org"
msg["Subject"] = "Reset your password"
msg["X-Yeap-Category"] = "password-reset"
msg.set_content("Click the link to reset your password: https://example.com/reset/abc")

with smtplib.SMTP("smtp.tm.yeapcloud.net", 587) as s:
    s.starttls()
    s.login("apikey", "ytm_your_api_key")
    s.send_message(msg)

SMTP 응답 코드

서버가 메시지를 거부하면 응답 코드로 이유를 알 수 있습니다. 4xx 코드는 일시적이므로 나중에 다시 시도하십시오. 5xx 코드는 영구적이므로 원인을 해결한 후 다시 보내십시오.

코드메시지원인 및 조치
535 5.7.8Authentication failed / API key revoked사용자 이름이나 키가 잘못되었거나 키가 폐기되었습니다. 사용자 이름은 apikey여야 합니다.
454 4.7.0Temporary authentication failure / Too many authentication failures서버가 아직 준비되지 않았거나 IP의 로그인 실패 횟수가 너무 많습니다. 잠시 후 다시 시도하십시오.
451 4.7.1Stream is paused스트림이 자동으로 일시 중지되었습니다. 스트림에 표시된 사유를 확인하고 고객 지원에 문의하십시오.
550 5.7.1Stream is banned / suspended / terminated스트림이 차단되었거나, 구독이 정지되었거나, 해지되었습니다.
550 5.7.1From domain … is not verified for this stream도메인을 인증하거나, 도메인이 이 스트림과 공유되거나 연결되어 있는지 확인하십시오.
550 5.7.1Sandbox mode: recipient is not a verified address스트림이 샌드박스에 있습니다. 수신자를 인증하거나 본인 도메인으로 보내십시오.
550 5.7.1Recipient is on a suppression list / All recipients are suppressed주소가 억제되었습니다(반송, 스팸 신고, 수신 거부 또는 수동).
452 4.7.1Hourly sending limit reached, try later시간당 한도(또는 샌드박스 일일 한도)를 모두 사용했습니다. 다음 시간에 다시 시도하십시오.
550 5.7.1Monthly sending quota exhausted월간 발송량을 모두 사용했으며 초과 사용이 허용되지 않습니다. 무료 요금제이거나 초과 사용 지출 한도에 도달한 경우입니다.
452 4.5.3Too many recipients한 트랜잭션의 수신자가 1,000명을 넘었습니다.
553 5.1.3Invalid recipient address수신자 주소 형식이 잘못되었습니다.
554 5.7.1Message rejected: virus detected메시지에 바이러스가 포함되어 있었습니다. 스트림이 즉시 차단되고 모든 API 키가 폐기됩니다.
554 5.7.1Message rejected as spam콘텐츠가 스팸으로 판정되었습니다. 거부가 반복되면 스트림이 일시 중지됩니다.
451 4.3.0Content scanner unavailable, try again later마케팅 메일은 검사 후에만 수락됩니다. 나중에 다시 시도하십시오. 그 밖의 451 4.3.0 응답은 일시적인 서버 오류이므로 다시 시도하십시오.
554 5.6.0Malformed message headers메시지 헤더를 수정하십시오.

HTTP API

항목값
기본 URLhttps://api.tm.yeapcloud.net/v1(https://api.yeap.cloud/api/tm/v1로도 사용 가능)
인증Authorization: Bearer ytm_your_api_key
형식JSON 요청 및 응답 본문, Content-Type: application/json
요청 속도 제한API 키당 분당 600회 요청

오류가 발생하면 HTTP 상태 코드와 다음과 같은 본문이 반환됩니다.

json
{"error": {"code": "invalid_request", "message": "subject is required (single line)"}}
HTTP 상태error.code의미
400invalid_json, invalid_request본문이 JSON 객체가 아니거나, 배치가 비어 있거나 너무 큽니다
401unauthorizedAPI 키가 없거나, 형식이 잘못되었거나, 폐기되었거나, 알 수 없는 키입니다
403stream_paused, stream_banned, stream_suspended스트림에서 발송할 수 없습니다
403from_domain_unverified, invalid_fromFrom 도메인이 이 스트림에서 인증되지 않았거나 From 주소가 잘못되었습니다
403postal_address_required우편 주소가 없는 마케팅 스트림입니다. 마케팅 설정 탭에서 입력하십시오.
403virus첨부 파일에 바이러스가 포함되어 있었습니다. 스트림이 차단됩니다.
404not_found이 스트림에 해당 메시지가 없습니다
422invalid_request필드가 누락되었거나 잘못되었습니다. message에 해당 필드가 표시됩니다.
429rate_limited1분에 600회를 초과하여 요청했습니다. 속도를 줄이고 다시 시도하십시오.
503no_node현재 사용할 수 있는 발송 서버가 없습니다. 나중에 다시 시도하십시오.

메시지 발송: POST /v1/send

필드유형설명
fromstring필수. noreply@example.com 또는 Example <noreply@example.com>과 같은 주소 하나. 도메인은 스트림에서 인증되어 있어야 합니다.
tostring 또는 array필수. 주소 하나, 쉼표로 구분된 문자열 또는 배열. 배열 항목은 {"email": "...", "name": "..."} 객체일 수도 있습니다.
cc, bccstring 또는 array선택. to와 같은 형식. Bcc 주소는 헤더에 나타나지 않습니다.
reply_tostring 또는 array선택. Reply-To 주소.
subjectstring필수. 한 줄, 최대 998자.
html, textstring둘 중 하나 이상 필수. 최상의 결과를 위해 둘 다 보내십시오.
headersobject선택. {"X-Campaign": "spring"}과 같은 추가 헤더. 표준 헤더(From, To, Subject, Reply-To, Message-ID, List-Unsubscribe 등)는 여기서 설정할 수 없습니다.
attachmentsarray선택. 항목 {"filename": "invoice.pdf", "content_base64": "...", "type": "application/pdf"}. 최대 10개 파일, 총 10 MB.
categorystring선택. 영문자, 숫자, ., _, -, 최대 64자.
tagsarray of strings선택. 자체 필터링용 태그 최대 10개, 각 최대 64자.
track_opens, track_clicksboolean선택. 이 메시지에 대해 열람 추적(추적 픽셀)과 클릭 추적(t.tm.yeapcloud.net을 거치도록 링크 재작성)을 켜거나 끕니다. HTML 전용. 생략하면 스트림 기본값이 적용됩니다. 둘 다 기본적으로 꺼져 있습니다.
variablesobject선택. subject, html, text의 {{name}} 자리 표시자를 대체합니다. html에서는 값이 HTML 이스케이프됩니다. 알 수 없는 자리 표시자는 그대로 남습니다.

한 번의 호출에는 to, cc, bcc를 합쳐 최대 50명의 수신자를 지정할 수 있습니다. 각 수신자는 자체 메시지 ID를 가진 별도의 사본을 받습니다. 여러 사람에게 서로 다른 내용을 보내려면 배치 엔드포인트를 사용하십시오.

예제:

bash
curl -X POST https://api.tm.yeapcloud.net/v1/send \
  -H "Authorization: Bearer ytm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Example <noreply@example.com>",
    "to": ["alice@example.org"],
    "subject": "Your order {{order_id}} has shipped",
    "html": "<p>Hi {{name}}, your order is on its way.</p>",
    "text": "Hi {{name}}, your order is on its way.",
    "category": "shipping",
    "tags": ["order"],
    "variables": {"name": "Alice", "order_id": "A-1024"}
  }'

응답:

json
{
  "message_ids": ["01JAQ3Z9V8K4M2N6P7R5S1T0XW"],
  "rejected": []
}

message_ids에는 수락된 사본이 나열됩니다. rejected에는 발송되지 않은 수신자가 각각 rcpt와 reason과 함께 나열됩니다. 일부 또는 모든 수신자가 거부되어도 호출은 성공할 수 있으므로 항상 rejected를 확인하십시오.

reason의미
invalid_recipient주소가 잘못되었습니다
suppressed:<scope>:<reason>주소가 억제 목록에 있습니다. 예: suppressed:global:hard_bounce
sandbox_recipient_not_verified스트림이 샌드박스에 있으며 해당 수신자는 허용되지 않습니다
rate_limited_hourly, rate_limited_sandbox_or_hourly시간당 한도(또는 샌드박스 일일 한도)를 모두 사용했습니다
monthly_quota_exceeded월간 발송량을 모두 사용했으며 초과 사용이 허용되지 않습니다
enqueue_failed메시지를 대기열에 넣지 못했습니다. 할당량에서 차감되지 않습니다. 다시 시도하십시오.

requests를 사용한 Python 예제:

python
import requests

resp = requests.post(
    "https://api.tm.yeapcloud.net/v1/send",
    headers={"Authorization": "Bearer ytm_your_api_key"},
    json={
        "from": "Example <noreply@example.com>",
        "to": "alice@example.org",
        "subject": "Welcome",
        "html": "<p>Welcome aboard!</p>",
        "text": "Welcome aboard!",
        "category": "welcome",
    },
    timeout=30,
)
resp.raise_for_status()
result = resp.json()
print(result["message_ids"], result["rejected"])

대량 발송: POST /v1/batch

한 번의 요청으로 최대 500개의 메시지를 보냅니다. 각 항목에는 /v1/send와 같은 필드가 있습니다.

json
{
  "messages": [
    {"from": "noreply@example.com", "to": "a@example.org", "subject": "Hi A", "text": "Hello A"},
    {"from": "noreply@example.com", "to": "b@example.org", "subject": "Hi B", "text": "Hello B"}
  ]
}

응답에는 메시지마다 결과가 하나씩 같은 순서로 포함됩니다.

json
{
  "results": [
    {"index": 0, "message_ids": ["01JAQ..."], "rejected": []},
    {"index": 1, "error": {"code": "invalid_request", "message": "subject is required (single line)"}, "rejected": []}
  ]
}

메시지 조회: GET /v1/messages

쿼리 매개변수설명
status상태로 필터링: queued, delivered, deferred, bounced, complained, rejected 또는 failed
to수신자 주소로 필터링
since이 시각 이후(포함)에 생성된 메시지만, 예: 2026-10-01T00:00:00Z
limit페이지당 결과 수, 1–100(기본값 50)
before다음 페이지를 조회하려면 이전 응답의 next_before 값을 전달합니다

응답은 {"data": [...], "next_before": "..."}입니다. 마지막 페이지에서는 next_before가 null입니다. 메시지는 30일 동안 보관됩니다.

GET /v1/messages/{id}는 메시지 하나와 해당 이벤트를 반환합니다.

json
{
  "id": "01JAQ3Z9V8K4M2N6P7R5S1T0XW",
  "stream_id": 12,
  "source": "api",
  "to": "alice@example.org",
  "from": "Example <noreply@example.com>",
  "subject": "Welcome",
  "category": "welcome",
  "tags": [],
  "status": "delivered",
  "smtp_code": 250,
  "smtp_response": "250 2.0.0 OK",
  "opened_at": null,
  "clicked_at": null,
  "unsubscribed_at": null,
  "created_at": "2026-10-20 10:15:02",
  "updated_at": "2026-10-20 10:15:04",
  "events": [
    {"type": "delivered", "at": "2026-10-20 10:15:04", "rcpt": "alice@example.org", "smtp_code": 250, "mx": "mx.example.org"}
  ]
}

억제 목록: /v1/suppressions

이 엔드포인트는 API 키가 속한 스트림의 억제 목록을 관리합니다.

요청본문 또는 쿼리응답
GET /v1/suppressions쿼리 email(선택), limit(1–500, 기본값 100), offset{"data": [{"id", "scope", "email", "reason", "category", "note", "created_at"}]}
POST /v1/suppressions{"email": "..."} 또는 {"emails": [...]}(최대 1,000개), 선택적 category{"added": 2, "invalid": []}
DELETE /v1/suppressions{"email": "..."}, 선택적 category(본문 또는 쿼리){"removed": 1}

API로 추가한 주소의 사유는 manual입니다. 계정 전체 및 전역 억제 항목은 API로 변경할 수 없습니다. 억제 목록 및 수신 거부를 참조하십시오.

관련 문서

이 페이지가 도움이 되었습니까?