Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions examples/async/broadcasts_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@ async def main() -> None:
print(retrieved)

recipients_params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": broadcast["id"],
"type": "delivered",
}
recipients: resend.Broadcasts.RecipientsResponse = (
await resend.Broadcasts.recipients_async(recipients_params)
await resend.Broadcasts.recipients_async(broadcast["id"], recipients_params)
)
print("Broadcast recipients !\n")
print(f"Found {len(recipients['data'])} recipients")
Expand Down
3 changes: 1 addition & 2 deletions examples/broadcasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,10 @@
print(retrieved)

recipients_params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": broadcast["id"],
"type": "delivered",
}
recipients: resend.Broadcasts.RecipientsResponse = resend.Broadcasts.recipients(
recipients_params
broadcast["id"], recipients_params
)
print("Broadcast recipients !\n")
print(f"Found {len(recipients['data'])} recipients")
Expand Down
27 changes: 14 additions & 13 deletions resend/broadcasts/_broadcasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ class RecipientsParams(TypedDict):
"""RecipientsParams is the class that wraps the parameters for the recipients method.

Attributes:
broadcast_id (str): The ID of the broadcast.
type (BroadcastRecipientEventType): The recipient event type to filter by.
email (NotRequired[str]): Filter recipients by email address (substring match).
bounce_type (NotRequired[BroadcastRecipientBounceType]): Filter bounced recipients
Expand All @@ -256,10 +255,6 @@ class RecipientsParams(TypedDict):
before (NotRequired[str]): The ID before which we'll retrieve more recipients (for pagination).
"""

broadcast_id: str
"""
The ID of the broadcast.
"""
type: BroadcastRecipientEventType
"""
The recipient event type to filter by.
Expand Down Expand Up @@ -495,20 +490,22 @@ def get(cls, id: str) -> Broadcast:
return resp

@classmethod
def recipients(cls, params: RecipientsParams) -> RecipientsResponse:
def recipients(cls, id: str, params: RecipientsParams) -> RecipientsResponse:
"""
Retrieve a broadcast's recipients for a given event type.
see more: https://resend.com/docs/api-reference/broadcasts/list-broadcast-recipients

Args:
id (str): The broadcast ID
params (RecipientsParams): The recipients filter and pagination parameters

Returns:
RecipientsResponse: A list of broadcast recipient objects
"""
base_path = f"/broadcasts/{params['broadcast_id']}/recipients"
query_params = {k: v for k, v in params.items() if k != "broadcast_id"}
path = PaginationHelper.build_paginated_path(base_path, query_params)
base_path = f"/broadcasts/{id}/recipients"
path = PaginationHelper.build_paginated_path(
base_path, cast(Dict[Any, Any], params)
)
resp = request.Request[Broadcasts.RecipientsResponse](
path=path, params={}, verb="get"
).perform_with_content()
Expand Down Expand Up @@ -670,20 +667,24 @@ async def get_async(cls, id: str) -> Broadcast:
return resp

@classmethod
async def recipients_async(cls, params: RecipientsParams) -> RecipientsResponse:
async def recipients_async(
cls, id: str, params: RecipientsParams
) -> RecipientsResponse:
"""
Retrieve a broadcast's recipients for a given event type (async).
see more: https://resend.com/docs/api-reference/broadcasts/list-broadcast-recipients

Args:
id (str): The broadcast ID
params (RecipientsParams): The recipients filter and pagination parameters

Returns:
RecipientsResponse: A list of broadcast recipient objects
"""
base_path = f"/broadcasts/{params['broadcast_id']}/recipients"
query_params = {k: v for k, v in params.items() if k != "broadcast_id"}
path = PaginationHelper.build_paginated_path(base_path, query_params)
base_path = f"/broadcasts/{id}/recipients"
path = PaginationHelper.build_paginated_path(
base_path, cast(Dict[Any, Any], params)
)
resp = await AsyncRequest[Broadcasts.RecipientsResponse](
path=path, params={}, verb="get"
).perform_with_content()
Expand Down
28 changes: 16 additions & 12 deletions tests/broadcasts_async_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,12 @@ async def test_broadcasts_recipients_async(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "delivered",
}
recipients: resend.Broadcasts.RecipientsResponse = (
await resend.Broadcasts.recipients_async(params)
await resend.Broadcasts.recipients_async(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
)
assert recipients["object"] == "list"
assert recipients["has_more"] is False
Expand Down Expand Up @@ -274,10 +275,11 @@ async def test_broadcasts_recipients_async_opened_has_count(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "opened",
}
recipients = await resend.Broadcasts.recipients_async(params)
recipients = await resend.Broadcasts.recipients_async(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["contact_id"] is None
assert recipient["count"] == 3
Expand All @@ -304,12 +306,13 @@ async def test_broadcasts_recipients_async_clicked_has_clicked_links(
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "clicked",
"email": "carter",
"limit": 10,
}
recipients = await resend.Broadcasts.recipients_async(params)
recipients = await resend.Broadcasts.recipients_async(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["count"] == 2
assert recipient["clicked_links"] == [
Expand All @@ -335,11 +338,12 @@ async def test_broadcasts_recipients_async_bounced_has_bounce_type(
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "bounced",
"bounce_type": "permanent",
}
recipients = await resend.Broadcasts.recipients_async(params)
recipients = await resend.Broadcasts.recipients_async(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["bounce_type"] == "permanent"

Expand All @@ -355,22 +359,22 @@ async def test_broadcasts_recipients_async_raise_exception_when_not_found(
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "does-not-exist",
"type": "sent",
}
with pytest.raises(ResendError):
_ = await resend.Broadcasts.recipients_async(params)
_ = await resend.Broadcasts.recipients_async("does-not-exist", params)

async def test_should_recipients_broadcasts_async_raise_exception_when_no_content(
self,
) -> None:
self.set_mock_json(None)
params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "sent",
}
with pytest.raises(NoContentError):
_ = await resend.Broadcasts.recipients_async(params)
_ = await resend.Broadcasts.recipients_async(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)

async def test_broadcasts_clicked_links_async(self) -> None:
self.set_mock_json(
Expand Down
21 changes: 11 additions & 10 deletions tests/broadcasts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,10 @@ def test_broadcasts_recipients(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "delivered",
}
recipients: resend.Broadcasts.RecipientsResponse = resend.Broadcasts.recipients(
params
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
assert recipients["object"] == "list"
assert recipients["has_more"] is False
Expand Down Expand Up @@ -290,10 +289,11 @@ def test_broadcasts_recipients_opened_has_count(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "opened",
}
recipients = resend.Broadcasts.recipients(params)
recipients = resend.Broadcasts.recipients(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["contact_id"] is None
assert recipient["count"] == 3
Expand All @@ -318,12 +318,13 @@ def test_broadcasts_recipients_clicked_has_clicked_links(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "clicked",
"email": "carter",
"limit": 10,
}
recipients = resend.Broadcasts.recipients(params)
recipients = resend.Broadcasts.recipients(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["count"] == 2
assert recipient["clicked_links"] == [
Expand All @@ -347,11 +348,12 @@ def test_broadcasts_recipients_bounced_has_bounce_type(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"type": "bounced",
"bounce_type": "permanent",
}
recipients = resend.Broadcasts.recipients(params)
recipients = resend.Broadcasts.recipients(
"78261eea-8f8b-4381-83c6-79fa7120f1cf", params
)
recipient = recipients["data"][0]
assert recipient["bounce_type"] == "permanent"

Expand All @@ -365,11 +367,10 @@ def test_broadcasts_recipients_raise_exception_when_not_found(self) -> None:
)

params: resend.Broadcasts.RecipientsParams = {
"broadcast_id": "does-not-exist",
"type": "sent",
}
with self.assertRaises(ResendError):
_ = resend.Broadcasts.recipients(params)
_ = resend.Broadcasts.recipients("does-not-exist", params)

def test_broadcasts_clicked_links(self) -> None:
self.set_mock_json(
Expand Down
Loading