openemail.broadcasts
Bu ad alanındaki her yöntem: imzası, parametreleri, döndürdüğü değer ve bir örnek.
Yöntemler
One message sent to everybody in one or more audiences, a personalised copy for each person, with unsubscribe handled for you.
broadcasts.preview()
Count who a broadcast to some audiences would reach
def preview( body: BroadcastPreviewInput, *, api_key: str | None = None, timeout: float | None = None,) -> BroadcastPreviewResourceReturns the numbers send would work from, without sending or writing anything: recipients, the people a broadcast to these audiences would reach now, unsubscribed, the contacts skipped because they have unsubscribed from every one of these audiences they are in, and suppressed, the subscribed contacts skipped because their address is on the suppression list. A contact in several of the audiences counts once.
The count is taken at the moment of the call, so contacts who join or leave before a send change it. Only audienceIds is sent, so you can pass the same dict you are about to give send.
Parametreler
body['audienceIds']list[str]Zorunlu1 to 10 audience ids. One that names no audience in the workspace is a 404
audience_not_found.api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastPreviewResource with audienceIds as sent, recipients, unsubscribed and suppressed.
Örnek
from openemail.types import BroadcastCreate from openemail import openemail draft: BroadcastCreate = { 'audienceIds': ['aud_4c1b8e2a7d9f05c36b4e8a71', 'aud_7e3d9a1c5b2f84e06d9a3c51'], 'from': 'Acme <[email protected]>', 'subject': 'The September release', 'text': 'Hi {{firstName|there}}, here is what changed this month.',} reach = openemail.broadcasts.preview(draft)skipped = reach['unsubscribed'] + reach['suppressed']print(f'{reach["recipients"]} will get it, {skipped} skipped') if reach['recipients'] > 0: openemail.broadcasts.send(draft)Notlar
Needs only
audiences:read, so a key that cannot send can still show somebody the count.The SDK retries it after a network failure or a retryable status, since it changes nothing.
Şurada da var
broadcasts.send()
Send one message to everybody in one or more audiences
def send( body: BroadcastCreate, *, idempotency_key: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> SentBroadcastResourceCreates a broadcast: one message sent to every contact in the audiences you name, as a separate copy for each person. Every copy has exactly one recipient and no cc or bcc, so nobody sees who else it went to, and every copy is an ordinary email with its own msg_ id, events, tracking and webhooks. emails.list(broadcast_id=...) lists them. Copies are not filed in the Sent folder, because the broadcast is the record.
The call returns straight away with the broadcast queued, or scheduled when you pass scheduledAt, and the sending happens in the background, 50 people at a time. Poll get to follow status and counts as it goes.
Who gets it: every contact in at least one of audienceIds, counted once however many of them hold it, except a contact that has unsubscribed from every one of those audiences it is in, and except an address on the suppression list. A contact added to one of the audiences after this call but before the sending reaches it is included. counts.recipients is the estimate taken at the call, and preview returns the same count without sending.
subject, html and text take merge fields in double braces, filled in from each contact: firstName, lastName, name, email and unsubscribeUrl. Each takes a fallback after a bar, so {{firstName|there}} reads there for a contact with no name. The first name is the first word of the contact's name and the last name is the rest. Values are escaped in html, and any other {{…}} is left as written. With template, the same values are passed as props, but only the ones the template declares.
Every copy carries the one-click unsubscribe headers mail clients and the large mailbox providers look for. An html or text body that does not place the unsubscribeUrl merge field itself gets a one-line footer with the link, while a template is sent as it is, so put unsubscribeUrl in the template. Following the link marks the person unsubscribed in every audience this broadcast went to. Their other audiences, their contact and mail sent to them one message at a time are not affected.
The whole send is checked against the plan's monthly sends before anything is written. A broadcast the allowance cannot cover raises a 429 send_quota_exceeded and leaves nothing behind, and each copy counts as one send.
Parametreler
body['audienceIds']list[str]Zorunlu1 to 10 audience ids such as
aud_9f2c4b7e1a0d63d84c5f2e7b. A contact in several of them gets one copy. An id that names no audience in the workspace is a 404audience_not_foundand nothing is sent.body['from']RecipientInputZorunluSender as
[email protected],Acme <[email protected]>or a dict such as{'email': '[email protected]', 'name': 'Acme'}. It must be an address the key may send as, otherwise 403from_address_forbidden.body['replyTo']RecipientInputWhere replies go, the same for every copy, in any of the forms
fromtakes.body['subject']strRequired unless a template supplies it, at most 998 characters. Takes merge fields.
body['html']strHTML body, at most 1,000,000 characters, with merge fields. Without the
unsubscribeUrlmerge field in it, an unsubscribe footer is added.body['text']strPlain text body, at most 1,000,000 characters, with merge fields. Without the
unsubscribeUrlmerge field in it, an unsubscribe line is added.body['template']BroadcastCreateTemplateA stored template instead of
htmlandtext, never beside them: a dict withidand, optionally,version,propsandslots. The merge values reach it as props it declares, such asfirstNameandunsubscribeUrl.body['tracking']TrackingRequestOpen and link tracking for every copy, a dict with
opensandclicks. A field left out follows the address it is sent from when that address set it, and is on otherwise.body['tags']dict[str, str]Up to 8 tags as a dict, keys of 1 to 64 letters, digits,
_or-, values up to 256 characters. Every copy carries them, plusbroadcast_id, which the server adds.body['scheduledAt']datetime | strA
datetime, an ISO 8601 instant or a duration such asPT2HorP1D, in the future and at most 365 days out. Left out, the sending starts straight away.idempotency_keystrYour own key, 1 to 255 characters of letters, digits,
_,.,:or-. Left out, the SDK makes one for the call, so its own retries never send twice. Sending the same key again returns the broadcast it created instead of a new one, and the same key with a different body is a 422idempotency_key_reuse.api_keystrSends with this key instead of the client's.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
SentBroadcastResource, a BroadcastResource plus replayed, with id (brd_ plus 24 hex), status queued or scheduled, audienceIds, from, subject, scheduledAt, createdAt and counts, whose recipients is the estimate and whose other counts start at 0.
Örnek
from datetime import datetime, timedelta, timezone from openemail import openemail broadcast = openemail.broadcasts.send( { 'audienceIds': ['aud_4c1b8e2a7d9f05c36b4e8a71'], 'from': 'Acme <[email protected]>', 'subject': '{{firstName|Hello}}, the September release is out', 'html': '<p>Hi {{firstName|there}}, here is what changed this month.</p>' '<p><a href="{{unsubscribeUrl}}">Unsubscribe</a></p>', 'tags': {'campaign': 'release-2026-09'}, 'scheduledAt': datetime.now(timezone.utc) + timedelta(hours=2), }, idempotency_key='release-2026-09',) print(broadcast['id'], broadcast['status'], broadcast['replayed'])Notlar
Safe to retry. Every call carries an
Idempotency-Key, yours or one the SDK makes, so a retry after a network failure returns the broadcast the first attempt created, withreplayedset toTrue, instead of sending again. Keys are scoped to the API key or app that sent them. Reusing a key with a different body is a 422idempotency_key_reuse.Refusals: 422
no_recipientswhen the audiences are empty or everybody in them has unsubscribed or is suppressed, 409domain_not_sendablewhen thefromdomain cannot sign mail yet, 422 ontemplate.*when the template does not resolve. Each raisesOpenEmailApiErrorwith thatcode.No attachments, cc, bcc, translation or encryption. A body from
htmlortextand atemplatetogether are refused.A test key (
oe_test_) creates a broadcast whose copies are marked sent and delivered to nobody, like any test send.
Şurada da var
- API
POST /broadcasts- TypeScript
broadcasts.send()- Ruby
broadcasts.send- CLI
openemail broadcasts send
broadcasts.list()
List one page of broadcasts, newest first
def list( *, limit: int | None = None, cursor: str | None = None, audience_id: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> Page[BroadcastResource]Returns one page of the broadcasts in the workspace, newest first, each with live counts. audience_id= keeps the ones that were sent to that audience, alone or beside others.
Paging is keyset: limit= takes 1 to 100 and defaults to 25, and nextCursor, the id of the last broadcast on the page, goes back as cursor= while hasMore is True. Send the same audience_id= with every page. list_all and iterate do that walk for you.
The individual messages are not here. List the copies of one broadcast with emails.list(broadcast_id=...).
Parametreler
limitintRows per page, a whole number from 1 to 100. The server defaults to 25.
cursorstrThe
nextCursorfrom the previous page, a broadcast id. One that names no broadcast in the workspace is a 400invalid_cursor.audience_idstrOnly the broadcasts that included this audience. An id that names no audience returns an empty page.
api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
Page[BroadcastResource], a dict with items, hasMore and nextCursor. Each item has id, status, audienceIds, from, subject, counts and the timestamps.
Örnek
from openemail import openemail page = openemail.broadcasts.list(audience_id='aud_4c1b8e2a7d9f05c36b4e8a71', limit=10) for broadcast in page['items']: counts = broadcast['counts'] print(broadcast['subject'], broadcast['status'], f'{counts["sent"]}/{counts["recipients"]}') if page['hasMore']: print('next page starts after', page['nextCursor'])Notlar
A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.
Şurada da var
- API
GET /broadcasts- TypeScript
broadcasts.list()- Ruby
broadcasts.list- CLI
openemail broadcasts list
broadcasts.list_all()
Collect every broadcast into one list
def list_all( *, limit: int | None = None, cursor: str | None = None, audience_id: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> builtins.list[BroadcastResource]Follows nextCursor from page to page and returns every broadcast in the workspace as one list, newest first, or every one sent to audience_id= when you pass it. limit= sets the page size of each request, not the total.
Parametreler
limitintPage size per request, from 1 to 100, defaulting to 25 on the server.
cursorstrA broadcast id to start after.
audience_idstrOnly the broadcasts that included this audience.
api_keystrOverrides the client's API key for every page of this walk.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
list[BroadcastResource] holding every broadcast across all pages.
Örnek
from openemail import openemail broadcasts = openemail.broadcasts.list_all(limit=100) sent = sum(broadcast['counts']['sent'] for broadcast in broadcasts) print(f'{len(broadcasts)} broadcasts, {sent} copies sent')Notlar
A failure on any page raises, and the broadcasts already fetched are discarded.
Every row carries live counts, so collecting a long history reads the copies of every broadcast in it. Use
iterateto stop early.A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.
Şurada da var
- API
GET /broadcasts- TypeScript
broadcasts.listAll()- Ruby
broadcasts.list_all
broadcasts.iterate()
Stream broadcasts one at a time, newest first
def iterate( *, limit: int | None = None, cursor: str | None = None, audience_id: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> Iterator[BroadcastResource]Returns a generator that yields broadcasts one at a time, newest first, and requests the next page only once the current one is used up. Breaking out of the loop stops the requests, so this is the cheap way to find the latest broadcast that matches something the filters cannot express.
Parametreler
limitintPage size per request, from 1 to 100, defaulting to 25 on the server.
cursorstrA broadcast id to start after.
audience_idstrOnly the broadcasts that included this audience.
api_keystrOverrides the client's API key for every page of this walk.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
Iterator[BroadcastResource], a generator yielding one broadcast per step.
Örnek
from openemail import openemail for broadcast in openemail.broadcasts.iterate(): if broadcast['status'] == 'sending': print('still going:', broadcast['id'], broadcast['counts']['queued'], 'waiting') breakNotlar
The generator is lazy, so an abandoned loop costs only the pages it read.
A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.
Şurada da var
- API
GET /broadcasts- TypeScript
broadcasts.iterate()- Ruby
broadcasts.iterate
broadcasts.get()
Read one broadcast and how far it has got
def get( id: str, *, api_key: str | None = None, timeout: float | None = None,) -> BroadcastResourceReturns one broadcast with counts read live from its copies, which makes this the call to poll while it sends.
status moves from scheduled or queued to sending and settles on sent once every copy handed over has gone out or failed. It reads sending for as long as copies are still waiting, even after the last person was reached and completedAt was set. cancelled and failed are the other two ends, and on failed lastError says why: the from address can no longer be sent from, the template stopped resolving, the plan ran out part way, the sending itself kept failing, or not one copy could be written.
counts.recipients is the estimate taken when it was created. created is the copies written, one per person reached, skipped the people passed over because their address was suppressed by then, and failedToQueue the people whose copy could not be written. queued, sending, sent, failed and cancelled count the copies by the state each one is in now.
Parametreler
idstrZorunluA
brd_id fromsendorlist.api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastResource with id, status, mode, source, audienceIds, from, subject, counts, lastError, scheduledAt, startedAt, completedAt, cancelledAt, createdAt and updatedAt.
Örnek
import time from openemail import openemail broadcast = openemail.broadcasts.get('brd_5a8c1e3f7b2d94a06c8e1f3b') for _ in range(30): if broadcast['status'] in ('sent', 'cancelled', 'failed'): break time.sleep(5) broadcast = openemail.broadcasts.get(broadcast['id']) counts = broadcast['counts'] print(f'{counts["sent"]} of {counts["recipients"]} sent') print(broadcast['status'], broadcast['lastError'])Notlar
A missing broadcast raises
OpenEmailApiErrorwithis_not_foundset and codebroadcast_not_found. An id from another workspace is a 404 too.For who each copy went to and what happened to it, use
list_recipients,get_recipientreads one copy with its content, andstatssums it up.A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
- API
GET /broadcasts/{id}- TypeScript
broadcasts.get()- Ruby
broadcasts.get- CLI
openemail broadcasts get
broadcasts.stats()
Read how a broadcast performed
def stats( id: str, *, grain: TrackingGrain | None = None, offset_minutes: int | None = None, days: int | None = None, minutes: int | None = None, api_key: str | None = None, timeout: float | None = None,) -> BroadcastStatsResourceReturns the totals and a series for one broadcast. totals counts copies sent, delivered, bounced, complained (reported as spam) and failed, pending for the ones still waiting, and people who opened, clicked and unsubscribed, with opens and clicks as event counts. series is sparse and oldest first: one bucket per grain in which something happened, counting each person once at the first time it happened to them, so it adds up to the totals.
Pass days= or minutes= to also read what happened lately. window then counts the copies delivered, bounced, reported as spam, opened, clicked and unsubscribed inside it, and series keeps only its buckets, while totals still covers the whole broadcast. Without either, window is None.
Parametreler
idstrZorunluA
brd_id fromsendorlist.grainTrackingGrainBucket width:
minute,hourorday, defaulting tohour.offset_minutesintMinutes east of UTC to cut the buckets in, from -840 to 840. Pass
time.localtime().tm_gmtoff // 60for the local zone.daysintReads a window of this many days too, from 1 to 1095. It starts at the beginning of its first
grainbucket and ends now.minutesintThe window in minutes, from 1 to 1576800, which wins over
days=when both are sent.api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastStatsResource with broadcastId, grain, totals, window and series, each bucket a dict with bucket, delivered, opened, clicked and unsubscribed. window holds since, delivered, bounced, complained, opened, clicked and unsubscribed, or is None when no window was asked for.
Örnek
from openemail import openemail stats = openemail.broadcasts.stats('brd_5a8c1e3f7b2d94a06c8e1f3b', grain='day') totals = stats['totals']rate = totals['opened'] / totals['sent'] if totals['sent'] else 0 print(f'{rate:.0%} opened, {totals["clicks"]} clicks, {totals["unsubscribed"]} unsubscribed')Notlar
Read only, so the SDK retries it after a network failure like any other read.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
broadcasts.analytics()
Read how broadcasts did over a time window
def analytics( *, broadcast_ids: Sequence[str] | None = None, days: int | None = None, minutes: int | None = None, grain: TrackingGrain | None = None, offset_minutes: int | None = None, api_key: str | None = None, timeout: float | None = None,) -> BroadcastAnalyticsResourceReturns the numbers behind the Analytics tab of the Broadcasts page in one request: how the live broadcasts sent inside a window did, added up in totals and cut to grain in series, and one row per broadcast in broadcasts so they can be compared.
A copy counts when it was sent inside the window, and everything that happened to it afterwards counts with it, so an open today of a copy sent last week is in a 30 day window but not in a 1 day one. Test mode broadcasts are left out. totals and series add up the broadcasts named in broadcast_ids=, or every one when it is left out, while broadcasts always lists every broadcast in the window, newest first.
series is sparse and oldest first: a bucket in which nothing happened has no entry, so a chart must fill the gaps. It counts each person once, at the first time it happened to them. grain= sets the bucket width and the key shape, YYYY-MM-DD, YYYY-MM-DDTHH or YYYY-MM-DDTHH:MM, and offset_minutes= shifts the boundaries so days break where the reader's day does. The window starts at the beginning of its oldest bucket, reported as since, and ends now, reported as until.
Parametreler
broadcast_idsSequence[str]Up to 50 broadcast ids for
totalsandseriesto add up, sent comma separated. Leave it out, or pass an empty list, for every broadcast in the window. An id with no copy in the window adds nothing, and more than 50 is a 422.daysintWindow length in days, from 1 to 1095, defaulting to 30.
minutesintWindow length in minutes, from 1 to 1576800, which wins over
days=when both are sent.grainTrackingGrainBucket width:
minute,hourorday, defaulting today.offset_minutesintMinutes east of UTC to cut the buckets in, from -840 to 840, defaulting to 0. Pass
time.localtime().tm_gmtoff // 60for the local zone.api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastAnalyticsResource, a dict with object set to broadcast_analytics, since, until, grain, offsetMinutes, broadcastIds, totals, series and broadcasts. totals has broadcasts and the counts BroadcastStatsTotals has, each entry of series has bucket, sent, delivered, opened, clicked and unsubscribed, and each entry of broadcasts has id, subject, status, sentAt and the same counts.
Örnek
import time from openemail import openemail analytics = openemail.broadcasts.analytics( days=90, offset_minutes=time.localtime().tm_gmtoff // 60) totals = analytics['totals']rate = totals['opened'] / totals['delivered'] if totals['delivered'] else 0print(f'{totals["broadcasts"]} broadcasts, {rate:.0%} opened') for row in analytics['broadcasts']: print(row['subject'], row['sent'], row['opened'], row['clicked'])Notlar
Read only, so the SDK retries it after a network failure like any other read.
opened,clickedandunsubscribedcount people, whileopensandclickscount events.A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds, and the rest are left out as if they did not exist.
Şurada da var
broadcasts.list_recipients()
List who a broadcast went to and what happened to each copy
def list_recipients( id: str, *, limit: int | None = None, cursor: str | None = None, filter: BroadcastRecipientFilter | None = None, q: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> Page[BroadcastRecipientResource]Returns one page of the people a broadcast went to, one row per copy, sorted by address. Each row says the copy's status, when it was sent and delivered, whether it bounced or was reported as spam, how often it was opened and clicked, and whether the person unsubscribed from one of the broadcast's audiences after it went out.
Opens and clicks leave out image proxies and link scanners, and stay 0 when the broadcast went out with tracking off. emailId is the copy's msg_ id, which get_recipient reads with its content and emails.get reads as a sent email.
Parametreler
idstrZorunluA
brd_id fromsendorlist.limitintPage size, from 1 to 200. The server defaults to 50.
cursorstrThe
nextCursorof the previous page. Send the samefilter=andq=with it.filterBroadcastRecipientFilterKeeps one group:
pending,sent,delivered,opened,not_opened(sent and never opened),clicked,bounced,complained,failed(failed or cancelled) orunsubscribed.BROADCAST_RECIPIENT_FILTERSnames them.qstrSearches the address and the name, ignoring case.
api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
Page[BroadcastRecipientResource], a dict with items, hasMore and nextCursor. Each item has emailId, contactId, email, name, status, sentAt, deliveredAt, bouncedAt, complainedAt, failure, opens, firstOpenAt, clicks, firstClickAt and unsubscribedAt.
Örnek
from openemail import openemail page = openemail.broadcasts.list_recipients('brd_5a8c1e3f7b2d94a06c8e1f3b', filter='bounced') for recipient in page['items']: print(recipient['email'], recipient['bouncedAt'], recipient['failure'])Notlar
A missing broadcast raises
OpenEmailApiErrorwith codebroadcast_not_found.A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
broadcasts.list_all_recipients()
Collect everybody a broadcast went to into one list
def list_all_recipients( id: str, *, limit: int | None = None, cursor: str | None = None, filter: BroadcastRecipientFilter | None = None, q: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> builtins.list[BroadcastRecipientResource]Walks every page of list_recipients and returns every copy of the broadcast as one list, sorted by address. One request per page, with the same filter= and q= on each.
Parametreler
idstrZorunluA
brd_id fromsendorlist.limitintPage size for each request, from 1 to 200. The server defaults to 50.
cursorstrStarts the walk after this cursor instead of the first page.
filterBroadcastRecipientFilterKeeps one group:
pending,sent,delivered,opened,not_opened(sent and never opened),clicked,bounced,complained,failed(failed or cancelled) orunsubscribed.BROADCAST_RECIPIENT_FILTERSnames them.qstrSearches the address and the name, ignoring case.
api_keystrOverrides the client's API key for every page of this walk.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
list[BroadcastRecipientResource] holding every copy that matches.
Örnek
from openemail import openemail unopened = openemail.broadcasts.list_all_recipients( 'brd_5a8c1e3f7b2d94a06c8e1f3b', filter='not_opened') print(len(unopened), [recipient['email'] for recipient in unopened])Notlar
If any page fails, the call raises and the rows already fetched are discarded.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
broadcasts.iterate_recipients()
Walk everybody a broadcast went to, one copy at a time
def iterate_recipients( id: str, *, limit: int | None = None, cursor: str | None = None, filter: BroadcastRecipientFilter | None = None, q: str | None = None, api_key: str | None = None, timeout: float | None = None,) -> Iterator[BroadcastRecipientResource]Returns a generator that yields every copy of the broadcast one at a time, sorted by address, fetching the next page only when the loop asks for it. Breaking out of the loop stops the requests.
Parametreler
idstrZorunluA
brd_id fromsendorlist.limitintPage size for each request, from 1 to 200. The server defaults to 50.
cursorstrStarts after this cursor instead of the first page.
filterBroadcastRecipientFilterKeeps one group:
pending,sent,delivered,opened,not_opened(sent and never opened),clicked,bounced,complained,failed(failed or cancelled) orunsubscribed.BROADCAST_RECIPIENT_FILTERSnames them.qstrSearches the address and the name, ignoring case.
api_keystrOverrides the client's API key for every page of this walk.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
Iterator[BroadcastRecipientResource], a generator yielding one copy per step.
Örnek
from openemail import openemail clicked = openemail.broadcasts.iterate_recipients( 'brd_5a8c1e3f7b2d94a06c8e1f3b', filter='clicked') for recipient in clicked: print(recipient['email'], recipient['clicks'], recipient['firstClickAt'])Notlar
Memory stays flat however large the broadcast, because only one page is held at a time.
A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
broadcasts.get_recipient()
Read one person's copy of a broadcast
def get_recipient( id: str, email_id: str, *, api_key: str | None = None, timeout: float | None = None,) -> BroadcastRecipientContentResourceReturns one copy: the same row list_recipients gives, plus the subject, html and text exactly as that person received them, with the merge fields filled in and their own unsubscribe link. The HTML is from before open and click tracking was added.
Parametreler
idstrZorunluA
brd_id fromsendorlist.email_idstrZorunluThe
emailIdof the copy, fromlist_recipients.api_keystrOverrides the client's API key for this call only.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastRecipientContentResource: emailId, contactId, email, name, status, sentAt, deliveredAt, bouncedAt, complainedAt, failure, opens, firstOpenAt, clicks, firstClickAt and unsubscribedAt, plus subject, html and text.
Örnek
from openemail import OpenEmailApiError, openemail try: copy = openemail.broadcasts.get_recipient( 'brd_5a8c1e3f7b2d94a06c8e1f3b', 'msg_01dad25067bc4dac966d515d' )except OpenEmailApiError as error: if error.is_not_found: print('No such copy:', error.code) else: raiseelse: print(copy['subject'], copy['deliveredAt'], copy['opens'])Notlar
An
email_idthat is not a copy of this broadcast raisesOpenEmailApiErrorwith coderecipient_not_found.A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.
Şurada da var
broadcasts.cancel()
Stop a broadcast that is scheduled, queued or still sending
def cancel( id: str, *, api_key: str | None = None, timeout: float | None = None,) -> BroadcastResourceStops a broadcast that is scheduled, queued or sending, including one that has reached everybody while some copies are still waiting to go. Nobody else is added, and every copy still waiting is cancelled. A copy already being handed over finishes, and copies that have gone cannot be recalled, so counts.sent keeps them and counts.cancelled shows what was stopped.
Once every copy has gone out there is nothing left to stop, and the call raises a 409 broadcast_not_cancellable. A failed broadcast with copies still waiting can be cancelled to stop them, and one with nothing waiting is refused the same way. Cancelling a broadcast that is already cancelled returns it as it stands, so the call is safe to repeat, and the SDK retries it after a network failure.
Parametreler
idstrZorunluThe
brd_id to cancel.api_keystrCancels with this key instead of the client's.
timeoutfloatSeconds this call may take, the response included, before it raises
OpenEmailNetworkErrorwithis_timeout. It overrides the client'stimeoutfor this call, and0turns the limit off.
Döndürür
BroadcastResource in its new state, status cancelled with cancelledAt set and the copies counted by where each one ended up.
Örnek
from openemail import openemail scheduled = openemail.broadcasts.send( { 'audienceIds': ['aud_4c1b8e2a7d9f05c36b4e8a71'], 'from': '[email protected]', 'subject': 'Doors open on Friday', 'text': 'Hi {{firstName|there}}, doors open at nine.', 'scheduledAt': 'P1D', }) cancelled = openemail.broadcasts.cancel(scheduled['id']) print(cancelled['status'], cancelled['cancelledAt'], cancelled['counts']['cancelled'])Notlar
Cancelling a scheduled broadcast before
scheduledAtsends nothing at all.A cancelled broadcast stays cancelled. There is no resume, so send again to the audiences that still need it.
A key limited to particular addresses or domains cancels only broadcasts sent from an address or domain it holds. Any other id raises
broadcast_not_found, as if the broadcast did not exist.