문서로 건너뛰기
Ruby

브로드캐스트

`broadcasts.preview`, `send`, `list`, `list_all`, `iterate`, `get`, `list_recipients`, `list_all_recipients`, `iterate_recipients`, `get_recipient`, `stats`, `analytics`, `cancel`.

모든 메서드

broadcasts.rb
draft = {  audienceIds: ["aud_4c1b8e2a7d9f05c36b4e8a71"],  from: "Acme <[email protected]>",  subject: "{{firstName|Hello}}, the September release is out",  html: "<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>",  text: "Hi {{firstName|there}}, here is what changed this month. Unsubscribe: {{unsubscribeUrl}}",  tags: {campaign: "release-2026-09"}} reach = client.broadcasts.preview(draft)puts reach[:recipients], reach[:unsubscribed], reach[:suppressed] broadcast = client.broadcasts.send(draft) latest = client.broadcasts.get(broadcast[:id])while %w[scheduled queued sending].include?(latest[:status])  sleep 5  latest = client.broadcasts.get(broadcast[:id])end client.broadcasts.iterate_recipients(broadcast[:id]) do |copy|  puts copy[:email], copy[:status], copy[:opens], copy[:clicks]end bounced = client.broadcasts.list_recipients(broadcast[:id], filter: "bounced")bounced.items.each { |row| puts "#{row[:emailId]} #{row[:email]}" } copy = client.broadcasts.get_recipient(broadcast[:id], "msg_01dad25067bc4dac966d515d")puts copy[:subject], copy[:bouncedAt] stats = client.broadcasts.stats(broadcast[:id], grain: "day")puts stats.dig(:totals, :opened), stats.dig(:totals, :clicked), stats.dig(:totals, :unsubscribed) lately = client.broadcasts.stats(broadcast[:id], days: 1)puts lately.dig(:window, :opened) later = client.broadcasts.send(draft, scheduledAt: "P1D")client.broadcasts.cancel(later[:id]) history = client.broadcasts.list(audience_id: draft[:audienceIds].first)puts latest[:status], latest.dig(:counts, :sent), history.items.size month = client.broadcasts.analytics(days: 30)month[:broadcasts].each do |row|  puts row[:subject], row[:sent], row[:opened]end

브로드캐스트는 하나 이상의 오디언스에 있는 모든 사람에게 메시지 하나를 사람마다 별도의 사본으로 보냅니다. 각 사본의 받는 사람은 정확히 한 명이고 cc나 bcc가 없어서 누구도 또 누구에게 갔는지 볼 수 없으며, 각 사본은 자체 msg_ id, 이벤트, 추적, 웹훅이 있는 일반 이메일입니다. list_recipients로 각각 어떻게 되었는지와 함께 나열합니다. 브로드캐스트 자체가 기록이므로 사본은 보낸편지함에 보관되지 않습니다.

send는 곧바로 queued 상태의 브로드캐스트를, scheduledAt:을 주면 scheduled 상태로 반환하며 발송은 백그라운드에서 진행됩니다. send에는 emails:send와 audiences:read, preview에는 audiences:read가 필요합니다. list, list_all, iterate, get, list_recipients, list_all_recipients, iterate_recipients, get_recipient, stats, analytics에는 emails:read, cancel에는 emails:send가 필요합니다.

모든 send에는 Idempotency-Key가 붙습니다. idempotency_key:로 준 것이거나 gem이 만든 것이므로, 네트워크 장애 뒤의 재시도는 두 번 보내는 대신 첫 시도가 만든 브로드캐스트를 replayed가 true인 상태로 응답합니다. preview, get, cancel과 모든 읽기는 반복해도 안전하며 재시도됩니다.

schedule_broadcast.rb
broadcast = client.broadcasts.send(  audienceIds: ["aud_4c1b8e2a7d9f05c36b4e8a71"],  from: "Acme <[email protected]>",  subject: "Doors open on Friday",  text: "Hi {{firstName|there}}, doors open at nine. Unsubscribe: {{unsubscribeUrl}}",  scheduledAt: Time.now + 3600,  idempotency_key: "doors-open-2026-10") puts broadcast[:id], broadcast[:status], broadcast[:replayed]

브로드캐스트의 필드는 키워드 인자나 Hash 하나이며 API의 camelCase 이름(audienceIds:, scheduledAt:)을 그대로 씁니다. idempotency_key:와 api_key:는 호출의 옵션이며 필드로 보내지지 않습니다. Hash와 나란히 준 키워드 인자는 그 Hash에 병합되므로, send(draft, scheduledAt: "P1D")는 같은 초안을 하루 뒤에 보냅니다. scheduledAt:은 Time, DateTime, ISO 8601 문자열, 또는 PT2H 같은 기간을 받으며, Time은 UTC 시각으로 나갑니다. preview는 받은 것 중 audienceIds만 보내므로 send와 같은 Hash를 받습니다. 응답은 Symbol 키를 가진 Hash이므로 broadcast[:status]로 상태를 읽습니다.

병합 필드

subject, html, text는 사람마다 그 연락처에서 채워집니다. {{firstName}}은 연락처 이름의 첫 단어, {{lastName}}은 나머지, {{name}}은 전체 이름, {{email}}은 사본이 가는 주소, {{unsubscribeUrl}}은 그 사람의 구독을 해지하는 링크입니다.

각 필드는 막대 뒤에 대체 값을 받아 연락처에 값이 없을 때 쓰므로, 이름 없이 저장된 연락처에서 {{firstName|there}}는 "there"가 됩니다. html에서는 값이 이스케이프되고, 다른 {{…}}는 쓴 그대로 남습니다.

저장된 템플릿을 보내려면 html:과 text: 대신 template:을, id와 선택적인 version, props, slots를 가진 Hash로 넘기세요. 같은 다섯 값이 프롭으로 가지만 템플릿이 선언한 프롭만이므로, firstName을 선언한 템플릿은 그 값을 받고 선언하지 않은 템플릿은 그 때문에 거절되지 않습니다. props에 있는 것은 모든 사본에 똑같이 들어갑니다.

구독 해지

모든 사본에 원클릭 구독 해지 헤더가 붙어 메일 클라이언트가 자체 구독 해지 버튼을 보여 줄 수 있으며, 대형 메일함 제공자가 대량 메일에 요구하는 것이 이것입니다. {{unsubscribeUrl}}을 직접 넣지 않은 html이나 text 본문에는 링크가 든 한 줄짜리 바닥글이 붙습니다. 템플릿은 그대로 보내지므로 템플릿에 {{unsubscribeUrl}}을 넣으세요.

구독을 해지하면 그 브로드캐스트가 간 모든 오디언스에서 그 사람이 구독 해지로 표시되며, 오디언스 페이지에서 설명하듯 audiences.list_contacts가 그 사람 행의 unsubscribedAt으로 이를 보여 줍니다. 그 사람은 오디언스와 주소록에 남고, 다른 오디언스는 그대로이며, 한 통씩 보내는 메일은 계속 나갑니다. 오디언스에서 뺐다가 다시 넣으면 새로 구독 상태가 됩니다.

건너뛰는 대상

브로드캐스트는 audienceIds 중 적어도 하나에 있는 모든 연락처에, 몇 개에 있든 한 번 닿습니다. 그 오디언스 중 자신이 속한 모든 곳에서 구독을 해지한 연락처와, 바운스나 신고 때문에 또는 누가 추가해서 차단 목록에 있는 주소는 건너뜁니다. send 뒤 발송이 닿기 전에 오디언스에 추가된 연락처는 받습니다.

preview는 보내지 않고 같은 수, recipients, unsubscribed, suppressed를 돌려줍니다. 아무에게도 닿지 않을 send는 422 no_recipients를 OpenEmail::ValidationError로 발생시킵니다.

무엇이든 기록하기 전에 발송 전체가 요금제의 월간 발송량과 대조되므로, 할당량이 감당할 수 없는 브로드캐스트는 429 send_quota_exceeded를 OpenEmail::RateLimitError로 발생시키고 아무것도 남기지 않습니다. 사본 한 통이 한 번의 발송으로 계산됩니다.

상태와 진행

get은 사본에서 counts를 바로 읽으므로, 브로드캐스트가 발송되는 동안 위의 예제처럼 호출 사이에 sleep을 두고 폴링하세요. status는 scheduled나 queued에서 sending으로 가고, 넘긴 모든 사본이 나가거나 실패하면 sent에 머뭅니다. completedAt이 마지막 사람에게 닿았다고 알린 뒤에도 사본이 기다리는 동안에는 sending입니다. failed는 브로드캐스트 전체가 멈췄다는 뜻이며, lastError가 이유를 알려 줍니다: from 주소로 더 이상 보낼 수 없거나, 템플릿을 해석할 수 없게 되었거나, 요금제가 중간에 소진되었거나, 발송 자체가 계속 실패했거나, 사본을 한 통도 기록하지 못한 경우입니다.

cancel은 scheduled, queued, sending 상태인 브로드캐스트를 멈춥니다. 더 이상 아무도 추가되지 않고 아직 기다리는 모든 사본이 취소되지만, 나간 사본은 되돌릴 수 없습니다. 모든 사본이 나간 뒤의 cancel은 409 broadcast_not_cancellable을 OpenEmail::ConflictError로 발생시키고, 취소된 브로드캐스트를 취소하면 그 상태 그대로 반환합니다.

누구에게 닿았는지

list_recipients는 브로드캐스트를 받은 사람들을 사본마다 한 행씩 주소순으로 담은 OpenEmail::Page 하나를 items, has_more?, next_cursor와 함께 반환합니다. list_all_recipients는 모든 페이지를 훑어 Array 하나로 모으고, iterate_recipients는 사본을 하나씩 블록에 yield하며 루프가 요청할 때만 다음 페이지를 가져옵니다. 블록이 없으면 Enumerator를 반환합니다. limit:은 1에서 200까지이고 기본값은 50이며, cursor:는 같은 filter: 및 q:와 함께 돌려보냅니다.

`filter:`남기는 항목
pending아직 대기열에 있거나 예약되었거나 발송 중인 사본.
sent발송된 사본.
delivered받는 서버가 수락한 사본.
opened한 번 이상 열린 사본.
not_opened발송되었지만 한 번도 열리지 않은 사본.
clicked추적된 클릭이 한 번 이상 있는 사본.
bounced반송된 사본.
complained받는 사람이 스팸으로 신고한 사본.
failed실패했거나 취소된 사본.
unsubscribed브로드캐스트 발송 후 수신 거부한 사람.

OpenEmail::BROADCAST_RECIPIENT_FILTERS가 각 필터를 정의하고, q:는 주소와 이름을 대소문자 구분 없이 검색합니다. 열람과 클릭에는 이미지 프록시와 링크 스캐너가 만든 것이 빠지며, 추적을 끄고 보낸 브로드캐스트에서는 0으로 유지됩니다.

get_recipient(id, email_id)는 사본 하나를 반환합니다: 같은 행에 그 사람이 받은 그대로의 subject, html, text가 병합 필드가 채워지고 그 사람만의 수신 거부 링크가 붙은 상태로 더해집니다. 행의 emailId를 email_id로 전달하세요. HTML은 열람 및 클릭 추적을 넣기 전의 것입니다. 이 브로드캐스트의 사본이 아닌 email_id는 404 recipient_not_found를, 알 수 없는 브로드캐스트는 404 broadcast_not_found를 발생시키며, 둘 다 OpenEmail::NotFoundError입니다.

stats는 합계와 시계열을 반환합니다. totals는 sent, delivered, bounced, complained, failed 사본 수와 아직 대기 중인 사본을 나타내는 pending, 그리고 opened, clicked, unsubscribed한 사람 수를 세며, opens와 clicks는 이벤트 수입니다. series는 희소하며 오래된 순으로, 무언가 일어난 grain:(minute, hour 또는 day, 기본값 hour)마다 버킷이 하나씩 있고, UTC에서 동쪽으로 offset_minutes:만큼 떨어진 시간대로 나뉩니다. 현지 시간대에는 Time.now.utc_offset / 60을 전달하세요. 각 사람은 그 일이 처음 일어난 시점에 한 번만 세어지므로, 합하면 합계와 같습니다.

최근에 일어난 일도 읽으려면 stats에 days:나 minutes:를 전달하세요. 그러면 window가 그 기간 안에 배달, 반송, 스팸 신고, 열람, 클릭, 수신 거부된 것을 세고, series는 그 기간의 버킷만 남기며, totals는 여전히 브로드캐스트 전체를 다룹니다. 둘 다 없으면 window는 nil입니다.

특정 주소나 도메인으로 제한된 키는 자신이 가진 주소나 도메인에서 보낸 브로드캐스트에만 닿습니다. list, list_all, iterate는 나머지를 빼고, get, 수신자 메서드, stats, cancel은 그것들에 대해 404 broadcast_not_found를 발생시킵니다.

응답: 브로드캐스트

send, get, cancel은 각각 이것 하나를 Symbol 키를 가진 Hash로 반환하며, send는 replayed를 더합니다. list는 이것들의 OpenEmail::Page를 최신순으로 반환하고, list_all과 iterate는 모든 페이지를 훑습니다. preview는 audienceIds, recipients, unsubscribed, suppressed를 가진 Hash를 반환합니다. list_recipients는 수신자 행의 OpenEmail::Page를 반환하고, get_recipient는 내용이 담긴 행 하나를 반환하며, stats는 broadcastId, grain, totals, window, series를 가진 Hash를 반환합니다. analytics는 totals, series, 그리고 broadcasts에 브로드캐스트마다 한 행을 가진 Hash를 반환합니다. 시각은 ISO 8601 문자열이며, Time.iso8601로 파싱할 수 있습니다.

idString
영구 식별자로, `brd_` 뒤에 16진수 24자가 붙습니다.
statusString
`scheduled`, `queued`, `sending`, `sent`, `cancelled`, `failed` 중 하나입니다. `OpenEmail::BROADCAST_STATUSES`가 각각을 정의합니다.
modeString
만든 키에 따라 `live` 또는 `test`. 테스트 브로드캐스트의 사본은 보냄으로 표시되고 아무에게도 전달되지 않습니다.
sourceString
시작된 곳: 키는 `api`, 연결된 앱은 `oauth`, 앱은 `composer`, 어시스턴트는 `mcp`.
audienceIdsArray<String>
보낸 오디언스, 각각 한 번씩.
fromString
모든 사본을 보내는 주소.
subjectString
병합 필드까지 쓴 그대로의 제목. 템플릿이 제목을 제공하면 비어 있습니다.
countsHash
`recipients`는 `send` 때 잡은 추정치입니다. `created`는 기록된 사본 수, `skipped`는 그때 주소가 차단되어 있어 건너뛴 사람 수, `failedToQueue`는 사본을 기록하지 못한 사람 수입니다. `queued`, `sending`, `sent`, `failed`, `cancelled`는 각 사본이 지금 있는 상태별 수입니다.
lastErrorString or nil
브로드캐스트가 실패한 이유, 또는 기록하지 못한 가장 최근 사본과 그 이유. 문제가 없는 동안은 nil입니다.
scheduledAtString or nil
ISO-8601 UTC, 발송이 시작될 예정 시각. 바로 보낸 브로드캐스트는 nil입니다.
startedAtString or nil
ISO-8601 UTC, 발송이 처음 사람들에게 닿은 시각.
completedAtString or nil
ISO-8601 UTC, 마지막 사람에게 닿은 시각. 그 뒤에도 사본이 나가기를 기다릴 수 있습니다.
cancelledAtString or nil
ISO-8601 UTC, `cancel`이 멈춘 시각.
createdAtString
ISO-8601 UTC, `send`를 호출한 시각. 목록 순서를 정합니다.
updatedAtString
ISO-8601 UTC, 발송이 진행되면서 갱신됩니다.

응답: 수신자 행

list_recipients, list_all_recipients, iterate_recipients의 각 행으로, Symbol 키를 가진 Hash입니다. get_recipient가 반환하는 Hash에는 subject, html, text가 더해집니다.

emailIdString
이 사람의 사본의 `msg_` id. `get_recipient`는 내용과 함께 읽고, `emails.get`은 목록 및 조회 페이지에서 설명하듯 보낸 이메일로 읽습니다.
contactIdString or nil
사본을 받은 연락처. 그 뒤 연락처가 삭제되었으면 nil입니다.
emailString
사본이 간 주소.
nameString or nil
연락처에 있는 이름.
statusString
사본의 상태: `queued`, `scheduled`, `sending`, `sent`, `failed` 또는 `cancelled`.
sentAtString or nil
ISO-8601 UTC, 사본이 발송된 시각.
deliveredAtString or nil
ISO-8601 UTC, 받는 서버가 수락한 시각으로, 첫 `email.delivered`입니다.
bouncedAtString or nil
ISO-8601 UTC, 반송된 시각으로, 첫 `email.bounced`입니다.
complainedAtString or nil
ISO-8601 UTC, 받는 사람이 스팸으로 신고한 시각으로, 첫 `email.complained`입니다.
failureString or nil
사본이 실패했다면 그 이유.
opensInteger
기록된 열람 수로, 이미지 프록시와 스캐너가 만든 것은 빠집니다. 추적이 꺼져 있었으면 0입니다.
firstOpenAtString or nil
ISO-8601 UTC, 첫 열람.
clicksInteger
추적 링크에서 기록된 클릭 수로, 스캐너는 빠집니다.
firstClickAtString or nil
ISO-8601 UTC, 첫 클릭.
unsubscribedAtString or nil
ISO-8601 UTC, 발송 후 이 사람이 브로드캐스트의 오디언스 중 하나에서 링크를 통하거나 다른 방법으로 수신 거부한 시각.