Skip to content

Commit

Permalink
feat: Broadcasts endpoints (#127)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexandre Cisneiros <[email protected]>
  • Loading branch information
drish and Cisneiros authored Dec 17, 2024
1 parent ef13199 commit bf29fa8
Show file tree
Hide file tree
Showing 8 changed files with 472 additions and 3 deletions.
50 changes: 50 additions & 0 deletions examples/broadcasts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
from typing import List

import resend
import resend.broadcasts

if not os.environ["RESEND_API_KEY"]:
raise EnvironmentError("RESEND_API_KEY is missing")

# replace with some existing audience id
audience_id: str = "78b8d3bc-a55a-45a3-aee6-6ec0a5e13d7e"

create_params: resend.Broadcasts.CreateParams = {
"audience_id": audience_id,
"from": "[email protected]",
"subject": "Hello, world!",
"html": "<p>Hello, world!</p>",
"text": "Hello, world!",
"reply_to": ["[email protected]", "[email protected]"],
"name": "Hello, world!",
}

broadcast: resend.Broadcasts.CreateResponse = resend.Broadcasts.create(create_params)
print("Created broadcast !")
print(broadcast)

send_params: resend.Broadcasts.SendParams = {
"broadcast_id": broadcast["id"],
}
sent: resend.Broadcasts.SendResponse = resend.Broadcasts.send(send_params)
print("Sent broadcast !\n")
print(sent)

retrieved: resend.Broadcast = resend.Broadcasts.get(id=broadcast["id"])
print("retrieved broadcast !\n")
print(retrieved)

if retrieved["status"] == "draft":
removed: resend.Broadcasts.RemoveResponse = resend.Broadcasts.remove(
id=broadcast["id"]
)
print("Removed broadcast !\n")
print(removed)
print("\n")
else:
print("Broadcast is not in draft status, cannot remove it.\n")

list_response: resend.Broadcasts.ListResponse = resend.Broadcasts.list()
print("List of broadcasts !\n")
print(list_response)
8 changes: 6 additions & 2 deletions resend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from .api_keys._api_keys import ApiKeys
from .audiences._audience import Audience
from .audiences._audiences import Audiences
from .broadcasts._broadcast import Broadcast
from .broadcasts._broadcasts import Broadcasts
from .contacts._contact import Contact
from .contacts._contacts import Contacts
from .domains._domain import Domain
Expand All @@ -14,7 +16,7 @@
from .emails._emails import Emails
from .emails._tag import Tag
from .request import Request
from .version import get_version, __version__
from .version import __version__, get_version

# Config vars
api_key = os.environ.get("RESEND_API_KEY")
Expand All @@ -24,7 +26,7 @@
from .emails._emails import Emails # noqa

__all__ = [
"__version__"
"__version__",
"get_version",
"Request",
"Emails",
Expand All @@ -33,6 +35,7 @@
"Batch",
"Audiences",
"Contacts",
"Broadcasts",
# Types
"Audience",
"Contact",
Expand All @@ -41,4 +44,5 @@
"Email",
"Attachment",
"Tag",
"Broadcast",
]
58 changes: 58 additions & 0 deletions resend/broadcasts/_broadcast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from typing import List, Union

from typing_extensions import TypedDict

# Uses functional typed dict syntax here in order to support "from" reserved keyword
_FromParam = TypedDict(
"_FromParam",
{
"from": str,
},
)


class Broadcast(_FromParam):
object: str
"""
The object type, which is always "broadcast".
"""
id: str
"""
The unique identifier of the broadcast.
"""
audience_id: str
"""
The unique identifier of the audience.
"""
name: str
"""
The name of the broadcast.
"""
subject: str
"""
The subject of the broadcast.
"""
reply_to: Union[List[str], str]
"""
The reply-to email address.
"""
preview_text: str
"""
The preview text of the broadcast.
"""
status: str
"""
The status of the broadcast.
"""
created_at: str
"""
The date and time the broadcast was created.
"""
scheduled_at: str
"""
The date and time the broadcast is scheduled to be sent.
"""
sent_at: str
"""
The date and time the broadcast was sent.
"""
240 changes: 240 additions & 0 deletions resend/broadcasts/_broadcasts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
from typing import Any, Dict, List, Union, cast

from typing_extensions import NotRequired, TypedDict

from resend import request

from ._broadcast import Broadcast

# _CreateParamsFrom is declared with functional TypedDict syntax here because
# "from" is a reserved keyword in Python, and this is the best way to
# support type-checking for it.
_CreateParamsFrom = TypedDict(
"_CreateParamsFrom",
{
"from": str,
},
)


class _CreateResponse(TypedDict):
id: str
"""
id of the created broadcast
"""


class _SendResponse(_CreateResponse):
pass


class _RemoveResponse(TypedDict):
object: str
"""
object type: "broadcast"
"""
id: str
"""
id of the removed broadcast
"""
deleted: bool
"""
True if the broadcast was deleted
"""


class _ListResponse(TypedDict):
object: str
"""
object type: "list"
"""
data: List[Broadcast]
"""
A list of broadcast objects
"""


class _CreateParamsDefault(_CreateParamsFrom):
audience_id: str
"""
The ID of the audience you want to send to.
"""
subject: str
"""
Email subject.
"""
reply_to: NotRequired[Union[List[str], str]]
"""
Reply-to email address. For multiple addresses, send as an array of strings.
"""
html: NotRequired[str]
"""
The HTML version of the message.
"""
text: NotRequired[str]
"""
The text version of the message.
"""
name: NotRequired[str]
"""
The friendly name of the broadcast. Only used for internal reference.
"""


class _SendBroadcastParams(TypedDict):
broadcast_id: str
"""
The ID of the broadcast to send.
"""
scheduled_at: NotRequired[str]
"""
Schedule email to be sent later.
The date should be in natural language (e.g.: in 1 min) or ISO 8601 format (e.g: 2024-08-05T11:52:01.858Z).
"""


class Broadcasts:

class CreateParams(_CreateParamsDefault):
"""CreateParams is the class that wraps the parameters for the create method.
Attributes:
from (str): The sender email address
audience_id (str): The ID of the audience you want to send to.
subject (str): Email subject.
reply_to (NotRequired[Union[List[str], str]]): Reply-to email address(es).
html (NotRequired[str]): The HTML version of the message.
text (NotRequired[str]): The text version of the message.
name (NotRequired[str]): The friendly name of the broadcast. Only used for internal reference.
"""

class SendParams(_SendBroadcastParams):
"""SendParams is the class that wraps the parameters for the send method.
Attributes:
broadcast_id (str): The ID of the broadcast to send.
scheduled_at (NotRequired[str]): Schedule email to be sent later.
The date should be in natural language (e.g.: in 1 min) or ISO 8601 format (e.g: 2024-08-05T11:52:01.858Z).
"""

class CreateResponse(_CreateResponse):
"""
CreateResponse is the class that wraps the response of the create method.
Attributes:
id (str): id of the created broadcast
"""

class SendResponse(_SendResponse):
"""
SendResponse is the class that wraps the response of the send method.
Attributes:
id (str): id of the created broadcast
"""

class ListResponse(_ListResponse):
"""
ListResponse is the class that wraps the response of the list method.
Attributes:
object (str): object type: "list"
data (List[Broadcast]): A list of broadcast objects
"""

class RemoveResponse(_RemoveResponse):
"""
RemoveResponse is the class that wraps the response of the remove method.
Attributes:
object (str): object type: "broadcast"
id (str): id of the removed broadcast
deleted (bool): True if the broadcast was deleted
"""

@classmethod
def create(cls, params: CreateParams) -> CreateResponse:
"""
Create a broadcast.
see more: https://resend.com/docs/api-reference/broadcasts/create-broadcast
Args:
params (CreateParams): The broadcast creation parameters
Returns:
CreateResponse: The new broadcast object response
"""
path = "/broadcasts"
resp = request.Request[_CreateResponse](
path=path, params=cast(Dict[Any, Any], params), verb="post"
).perform_with_content()
return resp

@classmethod
def send(cls, params: SendParams) -> SendResponse:
"""
Sends a broadcast.
see more: https://resend.com/docs/api-reference/broadcasts/send-broadcast
Args:
params (CreateParams): The broadcast creation parameters
Returns:
SendResponse: The new broadcast object response
"""
path = f"/broadcasts/{params['broadcast_id']}/send"
resp = request.Request[_SendResponse](
path=path, params=cast(Dict[Any, Any], params), verb="post"
).perform_with_content()
return resp

@classmethod
def list(cls) -> ListResponse:
"""
Retrieve a list of broadcasts.
see more: https://resend.com/docs/api-reference/broadcasts/list-broadcasts
Returns:
ListResponse: A list of broadcast objects
"""
path = "/broadcasts/"
resp = request.Request[_ListResponse](
path=path, params={}, verb="get"
).perform_with_content()
return resp

@classmethod
def get(cls, id: str) -> Broadcast:
"""
Retrieve a single broadcast.
see more: https://resend.com/docs/api-reference/broadcasts/get-broadcast
Args:
id (str): The broadcast ID
Returns:
Broadcast: The broadcast object
"""
path = f"/broadcasts/{id}"
resp = request.Request[Broadcast](
path=path, params={}, verb="get"
).perform_with_content()
return resp

@classmethod
def remove(cls, id: str) -> RemoveResponse:
"""
Delete a single broadcast.
see more: https://resend.com/docs/api-reference/broadcasts/delete-broadcasts
Args:
id (str): The broadcast ID
Returns:
RemoveResponse: The remove response object
"""
path = f"/broadcasts/{id}"
resp = request.Request[_RemoveResponse](
path=path, params={}, verb="delete"
).perform_with_content()
return resp
Empty file added resend/broadcasts/_init.py
Empty file.
Empty file added resend/broadcasts/py.typed
Empty file.
2 changes: 1 addition & 1 deletion resend/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.5.0"
__version__ = "2.6.0"


def get_version() -> str:
Expand Down
Loading

0 comments on commit bf29fa8

Please sign in to comment.