diff --git a/examples/batch_email_send.py b/examples/batch_email_send.py
index 02ae6fa..75eaf23 100644
--- a/examples/batch_email_send.py
+++ b/examples/batch_email_send.py
@@ -24,10 +24,28 @@
]
try:
+ # Send batch emails
+ print("sending without idempotency_key")
emails: resend.Batch.SendResponse = resend.Batch.send(params)
for email in emails["data"]:
print(f"Email id: {email['id']}")
-except resend.exceptions.ResendError as e:
+except resend.exceptions.ResendError as err:
print("Failed to send batch emails")
- print(f"Error: {e}")
+ print(f"Error: {err}")
+ exit(1)
+
+try:
+ # Send batch emails with idempotency_key
+ print("sending with idempotency_key")
+
+ options: resend.Batch.SendOptions = {
+ "idempotency_key": "af477dc78aa9fa91fff3b8c0d4a2e1a5",
+ }
+
+ e: resend.Batch.SendResponse = resend.Batch.send(params, options=options)
+ for email in e["data"]:
+ print(f"Email id: {email['id']}")
+except resend.exceptions.ResendError as err:
+ print("Failed to send batch emails")
+ print(f"Error: {err}")
exit(1)
diff --git a/resend/emails/_batch.py b/resend/emails/_batch.py
index 0c8c194..a79c2f5 100644
--- a/resend/emails/_batch.py
+++ b/resend/emails/_batch.py
@@ -1,6 +1,6 @@
-from typing import Any, Dict, List, cast
+from typing import Any, Dict, List, Optional, cast
-from typing_extensions import TypedDict
+from typing_extensions import NotRequired, TypedDict
from resend import request
@@ -8,6 +8,15 @@
from ._emails import Emails
+class _SendOptions(TypedDict):
+ idempotency_key: NotRequired[str]
+ """
+ Unique key that ensures the same operation is not processed multiple times.
+ Allows for safe retries without duplicating operations.
+ If provided, will be sent as the `Idempotency-Key` header.
+ """
+
+
class _SendResponse(TypedDict):
data: List[Email]
"""
@@ -17,6 +26,16 @@ class _SendResponse(TypedDict):
class Batch:
+ class SendOptions(_SendOptions):
+ """
+ SendOptions is the class that wraps the options for the batch send method.
+
+ Attributes:
+ idempotency_key (NotRequired[str]): Unique key that ensures the same operation is not processed multiple times.
+ Allows for safe retries without duplicating operations.
+ If provided, will be sent as the `Idempotency-Key` header.
+ """
+
class SendResponse(_SendResponse):
"""
SendResponse type that wraps a list of email objects
@@ -26,13 +45,16 @@ class SendResponse(_SendResponse):
"""
@classmethod
- def send(cls, params: List[Emails.SendParams]) -> SendResponse:
+ def send(
+ cls, params: List[Emails.SendParams], options: Optional[SendOptions] = None
+ ) -> SendResponse:
"""
Trigger up to 100 batch emails at once.
see more: https://resend.com/docs/api-reference/emails/send-batch-emails
Args:
params (List[Emails.SendParams]): The list of emails to send
+ options (Optional[SendOptions]): Batch options, ie: idempotency_key
Returns:
SendResponse: A list of email objects
@@ -40,6 +62,9 @@ def send(cls, params: List[Emails.SendParams]) -> SendResponse:
path = "/emails/batch"
resp = request.Request[_SendResponse](
- path=path, params=cast(List[Dict[Any, Any]], params), verb="post"
+ path=path,
+ params=cast(List[Dict[Any, Any]], params),
+ verb="post",
+ options=cast(Dict[Any, Any], options),
).perform_with_content()
return resp
diff --git a/tests/batch_emails_test.py b/tests/batch_emails_test.py
index 006a2a9..ced4fa3 100644
--- a/tests/batch_emails_test.py
+++ b/tests/batch_emails_test.py
@@ -38,6 +38,40 @@ def test_batch_email_send(self) -> None:
assert emails["data"][0]["id"] == "ae2014de-c168-4c61-8267-70d2662a1ce1"
assert emails["data"][1]["id"] == "faccb7a5-8a28-4e9a-ac64-8da1cc3bc1cb"
+ def test_batch_email_send_with_options(self) -> None:
+ self.set_mock_json(
+ {
+ "data": [
+ {"id": "ae2014de-c168-4c61-8267-70d2662a1ce1"},
+ {"id": "faccb7a5-8a28-4e9a-ac64-8da1cc3bc1cb"},
+ ]
+ }
+ )
+
+ params: List[resend.Emails.SendParams] = [
+ {
+ "from": "from@resend.dev",
+ "to": ["to@resend.dev"],
+ "subject": "hey",
+ "html": "hello, world!",
+ },
+ {
+ "from": "from@resend.dev",
+ "to": ["to@resend.dev"],
+ "subject": "hello",
+ "html": "hello, world!",
+ },
+ ]
+
+ options: resend.Emails.SendOptions = {
+ "idempotency_key": "af477dc78aa9fa91fff3b8c0d4a2e1a5",
+ }
+
+ emails: resend.Batch.SendResponse = resend.Batch.send(params, options=options)
+ assert len(emails["data"]) == 2
+ assert emails["data"][0]["id"] == "ae2014de-c168-4c61-8267-70d2662a1ce1"
+ assert emails["data"][1]["id"] == "faccb7a5-8a28-4e9a-ac64-8da1cc3bc1cb"
+
def test_should_send_batch_email_raise_exception_when_no_content(self) -> None:
self.set_mock_json(None)
params: List[resend.Emails.SendParams] = [