Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Broadcasts endpoints #127

Merged
merged 17 commits into from
Dec 17, 2024
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
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
Loading