diff --git a/examples/sending.py b/examples/sending.py index 97295a7..9f0ecb6 100644 --- a/examples/sending.py +++ b/examples/sending.py @@ -30,15 +30,54 @@ }, ) +batch_mail = mt.BatchSendEmailParams( + base=mt.BatchMail( + sender=mt.Address(email="", name=""), + subject="You are awesome!", + text="Congrats for sending test email with Mailtrap!", + category="Integration Test", + ), + requests=[ + mt.BatchEmailRequest( + to=[mt.Address(email="")], + ), + ], +) + +batch_mail_from_template = mt.BatchSendEmailParams( + base=mt.BatchMailFromTemplate( + sender=mt.Address(email="", name=""), + template_uuid="", + template_variables={ + "company_info_name": "Test_Company_info_name", + "name": "Test_Name", + "company_info_address": "Test_Company_info_address", + "company_info_city": "Test_Company_info_city", + "company_info_zip_code": "Test_Company_info_zip_code", + "company_info_country": "Test_Company_info_country", + }, + ), + requests=[ + mt.BatchEmailRequest( + to=[mt.Address(email="")], + subject="You are awesome!", + text="Congrats for sending test email with Mailtrap!", + category="Integration Test", + ), + ], +) + def send(client: mt.MailtrapClient, mail: mt.BaseMail) -> mt.SEND_ENDPOINT_RESPONSE: return client.send(mail) -def batch_send(client: mt.MailtrapClient, mail: mt.BaseMail) -> mt.SEND_ENDPOINT_RESPONSE: - # will be added soon - pass +def batch_send( + client: mt.MailtrapClient, mail: mt.BatchSendEmailParams +) -> mt.BATCH_SEND_ENDPOINT_RESPONSE: + return client.batch_send(mail=mail) if __name__ == "__main__": print(send(default_client, mail)) + print(batch_send(default_client, batch_mail)) diff --git a/mailtrap/__init__.py b/mailtrap/__init__.py index b4844fd..b1cfada 100644 --- a/mailtrap/__init__.py +++ b/mailtrap/__init__.py @@ -1,3 +1,4 @@ +from .client import BATCH_SEND_ENDPOINT_RESPONSE from .client import SEND_ENDPOINT_RESPONSE from .client import MailtrapClient from .exceptions import APIError @@ -15,6 +16,10 @@ from .models.mail import Address from .models.mail import Attachment from .models.mail import BaseMail +from .models.mail import BatchEmailRequest +from .models.mail import BatchMail +from .models.mail import BatchMailFromTemplate +from .models.mail import BatchSendEmailParams from .models.mail import Disposition from .models.mail import Mail from .models.mail import MailFromTemplate diff --git a/mailtrap/api/sending.py b/mailtrap/api/sending.py index 06c0f58..6837e0d 100644 --- a/mailtrap/api/sending.py +++ b/mailtrap/api/sending.py @@ -1,8 +1,10 @@ from typing import Optional from mailtrap.http import HttpClient -from mailtrap.models.mail.base import BaseMail -from mailtrap.models.mail.base import SendingMailResponse +from mailtrap.models.mail import BaseMail +from mailtrap.models.mail import SendingMailResponse +from mailtrap.models.mail.batch_mail import BatchSendEmailParams +from mailtrap.models.mail.batch_mail import BatchSendResponse class SendingApi: @@ -10,14 +12,25 @@ def __init__(self, client: HttpClient, inbox_id: Optional[str] = None) -> None: self._inbox_id = inbox_id self._client = client - @property - def _api_url(self) -> str: - url = "/api/send" + def _get_api_url(self, base_url: str) -> str: if self._inbox_id: - return f"{url}/{self._inbox_id}" - return url + return f"{base_url}/{self._inbox_id}" + return base_url def send(self, mail: BaseMail) -> SendingMailResponse: """Send email (text, html, text&html, templates).""" - response = self._client.post(self._api_url, json=mail.api_data) + response = self._client.post(self._get_api_url("/api/send"), json=mail.api_data) return SendingMailResponse(**response) + + def batch_send(self, mail: BatchSendEmailParams) -> BatchSendResponse: + """ + Batch send email (text, html, text&html, templates). Please note that + the endpoint will return a 200-level http status, even when sending + for individual messages may fail. Users of this endpoint should check + the success and errors for each message in the response (the results + are ordered the same as the original messages - requests). Please note + that the endpoint accepts up to 500 messages per API call, and up to 50 MB + payload size, including attachments. + """ + response = self._client.post(self._get_api_url("/api/batch"), json=mail.api_data) + return BatchSendResponse(**response) diff --git a/mailtrap/client.py b/mailtrap/client.py index cf45e15..1881f0a 100644 --- a/mailtrap/client.py +++ b/mailtrap/client.py @@ -17,9 +17,14 @@ from mailtrap.exceptions import ClientConfigurationError from mailtrap.http import HttpClient from mailtrap.models.mail import BaseMail -from mailtrap.models.mail.base import SendingMailResponse +from mailtrap.models.mail import BatchSendResponse +from mailtrap.models.mail import SendingMailResponse +from mailtrap.models.mail.batch_mail import BatchSendEmailParams SEND_ENDPOINT_RESPONSE = dict[str, Union[bool, list[str]]] +BATCH_SEND_ENDPOINT_RESPONSE = dict[ + str, Union[bool, list[str], list[dict[str, Union[bool, list[str]]]]] +] class MailtrapClient: @@ -93,6 +98,13 @@ def send(self, mail: BaseMail) -> SEND_ENDPOINT_RESPONSE: TypeAdapter(SendingMailResponse).dump_python(sending_response), ) + def batch_send(self, mail: BatchSendEmailParams) -> BATCH_SEND_ENDPOINT_RESPONSE: + batch_sending_response = self.sending_api.batch_send(mail) + return cast( + BATCH_SEND_ENDPOINT_RESPONSE, + TypeAdapter(BatchSendResponse).dump_python(batch_sending_response), + ) + @property def base_url(self) -> str: warnings.warn( diff --git a/mailtrap/models/mail/__init__.py b/mailtrap/models/mail/__init__.py index 2baa04c..b462d6a 100644 --- a/mailtrap/models/mail/__init__.py +++ b/mailtrap/models/mail/__init__.py @@ -1,15 +1,29 @@ from mailtrap.models.mail.address import Address from mailtrap.models.mail.attachment import Attachment from mailtrap.models.mail.attachment import Disposition -from mailtrap.models.mail.base import BaseMail -from mailtrap.models.mail.from_template import MailFromTemplate +from mailtrap.models.mail.batch_mail import BaseBatchMail +from mailtrap.models.mail.batch_mail import BatchEmailRequest +from mailtrap.models.mail.batch_mail import BatchMail +from mailtrap.models.mail.batch_mail import BatchMailFromTemplate +from mailtrap.models.mail.batch_mail import BatchSendEmailParams +from mailtrap.models.mail.batch_mail import BatchSendResponse +from mailtrap.models.mail.mail import BaseMail from mailtrap.models.mail.mail import Mail +from mailtrap.models.mail.mail import MailFromTemplate +from mailtrap.models.mail.mail import SendingMailResponse __all__ = [ "Address", "Attachment", - "Disposition", + "BaseBatchMail", "BaseMail", + "BatchEmailRequest", + "BatchMail", + "BatchMailFromTemplate", + "BatchSendEmailParams", + "BatchSendResponse", + "Disposition", "Mail", "MailFromTemplate", + "SendingMailResponse", ] diff --git a/mailtrap/models/mail/base.py b/mailtrap/models/mail/base.py deleted file mode 100644 index 5964583..0000000 --- a/mailtrap/models/mail/base.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any -from typing import Optional - -from pydantic import Field -from pydantic.dataclasses import dataclass - -from mailtrap.models.common import RequestParams -from mailtrap.models.mail.address import Address -from mailtrap.models.mail.attachment import Attachment - - -@dataclass -class BaseMail(RequestParams): - sender: Address = Field(..., serialization_alias="from") - to: list[Address] = Field(...) - cc: Optional[list[Address]] = None - bcc: Optional[list[Address]] = None - attachments: Optional[list[Attachment]] = None - headers: Optional[dict[str, str]] = None - custom_variables: Optional[dict[str, Any]] = None - - -@dataclass -class SendingMailResponse: - success: bool - message_ids: list[str] diff --git a/mailtrap/models/mail/batch_mail.py b/mailtrap/models/mail/batch_mail.py new file mode 100644 index 0000000..0b8ab51 --- /dev/null +++ b/mailtrap/models/mail/batch_mail.py @@ -0,0 +1,69 @@ +from typing import Any +from typing import Optional +from typing import Union + +from pydantic import Field +from pydantic.dataclasses import dataclass + +from mailtrap.models.common import RequestParams +from mailtrap.models.mail.address import Address +from mailtrap.models.mail.attachment import Attachment + + +@dataclass +class BaseBatchMail(RequestParams): + sender: Address = Field(..., serialization_alias="from") + attachments: Optional[list[Attachment]] = None + headers: Optional[dict[str, str]] = None + custom_variables: Optional[dict[str, Any]] = None + reply_to: Optional[Address] = None + + +@dataclass +class BatchMail(BaseBatchMail): + subject: str = Field(...) # type:ignore + text: Optional[str] = None + html: Optional[str] = None + category: Optional[str] = None + + +@dataclass +class BatchMailFromTemplate(BaseBatchMail): + template_uuid: str = Field(...) # type:ignore + template_variables: Optional[dict[str, Any]] = None + + +@dataclass +class BatchEmailRequest(BaseBatchMail): + to: list[Address] = Field(...) # type:ignore + sender: Optional[Address] = Field( + None, serialization_alias="from" + ) # type: ignore[assignment] + cc: Optional[list[Address]] = None + bcc: Optional[list[Address]] = None + subject: Optional[str] = None + text: Optional[str] = None + html: Optional[str] = None + category: Optional[str] = None + template_uuid: Optional[str] = None + template_variables: Optional[dict[str, Any]] = None + + +@dataclass +class BatchSendEmailParams(RequestParams): + base: Union[BatchMail, BatchMailFromTemplate] + requests: list[BatchEmailRequest] + + +@dataclass +class BatchSendResponseItem: + success: bool + message_ids: Optional[list[str]] = None + errors: Optional[list[str]] = None + + +@dataclass +class BatchSendResponse: + success: bool + responses: list[BatchSendResponseItem] + errors: Optional[list[str]] = None diff --git a/mailtrap/models/mail/from_template.py b/mailtrap/models/mail/from_template.py deleted file mode 100644 index 35a8e29..0000000 --- a/mailtrap/models/mail/from_template.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any -from typing import Optional - -from pydantic import Field -from pydantic.dataclasses import dataclass - -from mailtrap.models.mail.base import BaseMail - - -@dataclass -class MailFromTemplate(BaseMail): - template_uuid: str = Field(...) # type:ignore - template_variables: Optional[dict[str, Any]] = None diff --git a/mailtrap/models/mail/mail.py b/mailtrap/models/mail/mail.py index b58077b..c55c130 100644 --- a/mailtrap/models/mail/mail.py +++ b/mailtrap/models/mail/mail.py @@ -1,9 +1,24 @@ +from typing import Any from typing import Optional from pydantic import Field from pydantic.dataclasses import dataclass -from mailtrap.models.mail.base import BaseMail +from mailtrap.models.common import RequestParams +from mailtrap.models.mail.address import Address +from mailtrap.models.mail.attachment import Attachment + + +@dataclass +class BaseMail(RequestParams): + to: list[Address] + sender: Address = Field(..., serialization_alias="from") + cc: Optional[list[Address]] = None + bcc: Optional[list[Address]] = None + attachments: Optional[list[Attachment]] = None + headers: Optional[dict[str, str]] = None + custom_variables: Optional[dict[str, Any]] = None + reply_to: Optional[Address] = None @dataclass @@ -12,3 +27,15 @@ class Mail(BaseMail): text: Optional[str] = None html: Optional[str] = None category: Optional[str] = None + + +@dataclass +class MailFromTemplate(BaseMail): + template_uuid: str = Field(...) # type:ignore + template_variables: Optional[dict[str, Any]] = None + + +@dataclass +class SendingMailResponse: + success: bool + message_ids: list[str] diff --git a/tests/unit/api/test_sending.py b/tests/unit/api/test_sending.py index 619419a..3de20c4 100644 --- a/tests/unit/api/test_sending.py +++ b/tests/unit/api/test_sending.py @@ -7,7 +7,11 @@ from mailtrap.api.sending import SendingApi from mailtrap.config import SENDING_HOST from mailtrap.http import HttpClient -from mailtrap.models.mail.base import SendingMailResponse +from mailtrap.models.mail import SendingMailResponse +from mailtrap.models.mail.batch_mail import BatchEmailRequest +from mailtrap.models.mail.batch_mail import BatchMail +from mailtrap.models.mail.batch_mail import BatchSendEmailParams +from mailtrap.models.mail.batch_mail import BatchSendResponse ACCOUNT_ID = "321" PROJECT_ID = 123 @@ -28,7 +32,26 @@ MAIL_ENTITIES = [DUMMY_MAIL, DUMMY_MAIL_FROM_TEMPLATE] +DUMMY_BATCH_MAIL = BatchMail( + sender=DUMMY_ADDRESS, + subject="Batch Email Subject", + text="Batch email text", + html="

Batch email HTML

", +) + +DUMMY_BATCH_REQUEST = BatchEmailRequest( + to=[DUMMY_ADDRESS], + subject="Individual Email Subject", + text="Individual email text", +) + +DUMMY_BATCH_PARAMS = BatchSendEmailParams( + base=DUMMY_BATCH_MAIL, + requests=[DUMMY_BATCH_REQUEST], +) + SEND_FULL_URL = f"https://{SENDING_HOST}/api/send" +BATCH_SEND_FULL_URL = f"https://{SENDING_HOST}/api/batch" def get_sending_api() -> SendingApi: @@ -95,3 +118,74 @@ def test_send_should_handle_success_response( assert len(responses.calls) == 1 request = responses.calls[0].request # type: ignore assert request.body == json.dumps(mail.api_data).encode() + + @responses.activate + def test_batch_send_should_raise_authorization_error(self) -> None: + response_body = {"errors": ["Unauthorized"]} + responses.post(BATCH_SEND_FULL_URL, json=response_body, status=401) + api = get_sending_api() + + with pytest.raises(mt.AuthorizationError): + api.batch_send(DUMMY_BATCH_PARAMS) + + @responses.activate + def test_batch_send_should_raise_api_error_for_400_status_code(self) -> None: + response_body = {"errors": ["Some error msg"]} + responses.post(BATCH_SEND_FULL_URL, json=response_body, status=400) + + api = get_sending_api() + + with pytest.raises(mt.APIError): + api.batch_send(DUMMY_BATCH_PARAMS) + + @responses.activate + def test_batch_send_should_raise_api_error_for_500_status_code(self) -> None: + response_body = {"errors": ["Some error msg"]} + responses.post(BATCH_SEND_FULL_URL, json=response_body, status=500) + + api = get_sending_api() + + with pytest.raises(mt.APIError): + api.batch_send(DUMMY_BATCH_PARAMS) + + @responses.activate + def test_batch_send_should_handle_success_response(self) -> None: + response_body = { + "success": True, + "responses": [{"success": True, "message_ids": ["12345"]}], + } + responses.post(BATCH_SEND_FULL_URL, json=response_body) + + api = get_sending_api() + result = api.batch_send(DUMMY_BATCH_PARAMS) + + assert isinstance(result, BatchSendResponse) + assert result.success is True + assert len(result.responses) == 1 + assert result.responses[0].success is True + assert result.responses[0].message_ids == ["12345"] + assert len(responses.calls) == 1 + request = responses.calls[0].request # type: ignore + assert request.body == json.dumps(DUMMY_BATCH_PARAMS.api_data).encode() + + @responses.activate + def test_batch_send_should_handle_partial_failure_response(self) -> None: + response_body = { + "success": True, + "responses": [ + {"success": True, "message_ids": ["12345"]}, + {"success": False, "errors": ["Invalid email address"]}, + ], + } + responses.post(BATCH_SEND_FULL_URL, json=response_body) + + api = get_sending_api() + result = api.batch_send(DUMMY_BATCH_PARAMS) + + assert isinstance(result, BatchSendResponse) + assert result.success is True + assert len(result.responses) == 2 + assert result.responses[0].success is True + assert result.responses[0].message_ids == ["12345"] + assert result.responses[1].success is False + assert result.responses[1].errors == ["Invalid email address"] diff --git a/tests/unit/models/mail/test_batch_mail.py b/tests/unit/models/mail/test_batch_mail.py new file mode 100644 index 0000000..91328c6 --- /dev/null +++ b/tests/unit/models/mail/test_batch_mail.py @@ -0,0 +1,153 @@ +from mailtrap.models.mail import Address +from mailtrap.models.mail import Attachment +from mailtrap.models.mail import BatchEmailRequest +from mailtrap.models.mail import BatchMail +from mailtrap.models.mail import BatchMailFromTemplate + + +class TestBatchMail: + ADDRESS = Address(email="joe@mail.com") + ADDRESS_API_DATA = {"email": "joe@mail.com"} + + ATTACHMENT = Attachment(content=b"base64_content", filename="file.txt") + ATTACHMENT_API_DATA = {"content": "base64_content", "filename": "file.txt"} + + def test_api_data_should_return_dict_with_required_props_only(self) -> None: + entity = BatchMail( + sender=self.ADDRESS, + subject="Email subject", + text="email text", + ) + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "subject": "Email subject", + "text": "email text", + } + + def test_api_data_should_return_dict_with_all_props(self) -> None: + entity = BatchMail( + sender=self.ADDRESS, + subject="Email subject", + text="email text", + html="email html", + attachments=[self.ATTACHMENT], + headers={"key": "value"}, + custom_variables={"var": 42}, + category="test_category", + reply_to=self.ADDRESS, + ) + + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "subject": "Email subject", + "text": "email text", + "html": "email html", + "attachments": [self.ATTACHMENT_API_DATA], + "headers": {"key": "value"}, + "custom_variables": {"var": 42}, + "category": "test_category", + "reply_to": self.ADDRESS_API_DATA, + } + + +class TestBatchMailFromTremplate: + ADDRESS = Address(email="joe@mail.com") + ADDRESS_API_DATA = {"email": "joe@mail.com"} + + ATTACHMENT = Attachment(content=b"base64_content", filename="file.txt") + ATTACHMENT_API_DATA = {"content": "base64_content", "filename": "file.txt"} + + def test_api_data_should_return_dict_with_required_props_only(self) -> None: + entity = BatchMailFromTemplate( + sender=self.ADDRESS, + template_uuid="fake_uuid", + ) + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "template_uuid": "fake_uuid", + } + + def test_api_data_should_return_dict_with_all_props(self) -> None: + entity = BatchMailFromTemplate( + sender=self.ADDRESS, + template_uuid="fake_uuid", + template_variables={"username": "Joe"}, + attachments=[self.ATTACHMENT], + headers={"key": "value"}, + custom_variables={"var": 42}, + reply_to=self.ADDRESS, + ) + + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "template_uuid": "fake_uuid", + "template_variables": {"username": "Joe"}, + "attachments": [self.ATTACHMENT_API_DATA], + "headers": {"key": "value"}, + "custom_variables": {"var": 42}, + "reply_to": self.ADDRESS_API_DATA, + } + + +class TestBatchEmailRequest: + ADDRESS = Address(email="joe@mail.com") + ADDRESS_API_DATA = {"email": "joe@mail.com"} + + ATTACHMENT = Attachment(content=b"base64_content", filename="file.txt") + ATTACHMENT_API_DATA = {"content": "base64_content", "filename": "file.txt"} + + def test_api_data_should_return_dict_with_required_props_only(self) -> None: + entity = BatchEmailRequest( + to=[self.ADDRESS], + ) + assert entity.api_data == {"to": [self.ADDRESS_API_DATA]} + + def test_api_data_should_return_dict_with_all_props_for_inline_mail(self) -> None: + entity = BatchEmailRequest( + sender=self.ADDRESS, + to=[self.ADDRESS], + subject="Email subject", + text="email text", + html="email html", + attachments=[self.ATTACHMENT], + headers={"key": "value"}, + custom_variables={"var": 42}, + category="test_category", + reply_to=self.ADDRESS, + ) + + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "to": [self.ADDRESS_API_DATA], + "subject": "Email subject", + "text": "email text", + "html": "email html", + "attachments": [self.ATTACHMENT_API_DATA], + "headers": {"key": "value"}, + "custom_variables": {"var": 42}, + "category": "test_category", + "reply_to": self.ADDRESS_API_DATA, + } + + def test_api_data_should_return_dict_with_all_props_for_template_mail(self) -> None: + entity = BatchEmailRequest( + sender=self.ADDRESS, + to=[self.ADDRESS], + attachments=[self.ATTACHMENT], + headers={"key": "value"}, + custom_variables={"var": 42}, + reply_to=self.ADDRESS, + template_uuid="fake_uuid", + template_variables={"username": "Joe"}, + ) + + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "to": [self.ADDRESS_API_DATA], + "attachments": [self.ATTACHMENT_API_DATA], + "headers": {"key": "value"}, + "custom_variables": {"var": 42}, + "reply_to": self.ADDRESS_API_DATA, + "template_uuid": "fake_uuid", + "template_variables": {"username": "Joe"}, + } diff --git a/tests/unit/models/mail/test_from_template.py b/tests/unit/models/mail/test_from_template.py deleted file mode 100644 index 853cd2b..0000000 --- a/tests/unit/models/mail/test_from_template.py +++ /dev/null @@ -1,48 +0,0 @@ -from mailtrap.models.mail import Address -from mailtrap.models.mail import Attachment -from mailtrap.models.mail import MailFromTemplate - - -class TestAttachment: - ADDRESS = Address(email="joe@mail.com") - ADDRESS_API_DATA = {"email": "joe@mail.com"} - - ATTACHMENT = Attachment(content=b"base64_content", filename="file.txt") - ATTACHMENT_API_DATA = {"content": "base64_content", "filename": "file.txt"} - - def test_api_data_should_return_dict_with_required_props_only(self) -> None: - entity = MailFromTemplate( - sender=self.ADDRESS, - to=[self.ADDRESS], - template_uuid="fake_uuid", - ) - assert entity.api_data == { - "from": self.ADDRESS_API_DATA, - "to": [self.ADDRESS_API_DATA], - "template_uuid": "fake_uuid", - } - - def test_api_data_should_return_dict_with_all_props(self) -> None: - entity = MailFromTemplate( - sender=self.ADDRESS, - to=[self.ADDRESS], - template_uuid="fake_uuid", - template_variables={"username": "Joe"}, - cc=[self.ADDRESS], - bcc=[self.ADDRESS], - attachments=[self.ATTACHMENT], - headers={"key": "value"}, - custom_variables={"var": 42}, - ) - - assert entity.api_data == { - "from": self.ADDRESS_API_DATA, - "to": [self.ADDRESS_API_DATA], - "template_uuid": "fake_uuid", - "template_variables": {"username": "Joe"}, - "cc": [self.ADDRESS_API_DATA], - "bcc": [self.ADDRESS_API_DATA], - "attachments": [self.ATTACHMENT_API_DATA], - "headers": {"key": "value"}, - "custom_variables": {"var": 42}, - } diff --git a/tests/unit/models/mail/test_mail.py b/tests/unit/models/mail/test_mail.py index 8afab27..7cbefb5 100644 --- a/tests/unit/models/mail/test_mail.py +++ b/tests/unit/models/mail/test_mail.py @@ -1,9 +1,10 @@ from mailtrap.models.mail import Address from mailtrap.models.mail import Attachment from mailtrap.models.mail import Mail +from mailtrap.models.mail import MailFromTemplate -class TestAttachment: +class TestMail: ADDRESS = Address(email="joe@mail.com") ADDRESS_API_DATA = {"email": "joe@mail.com"} @@ -52,3 +53,48 @@ def test_api_data_should_return_dict_with_all_props(self) -> None: "custom_variables": {"var": 42}, "category": "test_category", } + + +class TestMailFromTremplate: + ADDRESS = Address(email="joe@mail.com") + ADDRESS_API_DATA = {"email": "joe@mail.com"} + + ATTACHMENT = Attachment(content=b"base64_content", filename="file.txt") + ATTACHMENT_API_DATA = {"content": "base64_content", "filename": "file.txt"} + + def test_api_data_should_return_dict_with_required_props_only(self) -> None: + entity = MailFromTemplate( + sender=self.ADDRESS, + to=[self.ADDRESS], + template_uuid="fake_uuid", + ) + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "to": [self.ADDRESS_API_DATA], + "template_uuid": "fake_uuid", + } + + def test_api_data_should_return_dict_with_all_props(self) -> None: + entity = MailFromTemplate( + sender=self.ADDRESS, + to=[self.ADDRESS], + template_uuid="fake_uuid", + template_variables={"username": "Joe"}, + cc=[self.ADDRESS], + bcc=[self.ADDRESS], + attachments=[self.ATTACHMENT], + headers={"key": "value"}, + custom_variables={"var": 42}, + ) + + assert entity.api_data == { + "from": self.ADDRESS_API_DATA, + "to": [self.ADDRESS_API_DATA], + "template_uuid": "fake_uuid", + "template_variables": {"username": "Joe"}, + "cc": [self.ADDRESS_API_DATA], + "bcc": [self.ADDRESS_API_DATA], + "attachments": [self.ATTACHMENT_API_DATA], + "headers": {"key": "value"}, + "custom_variables": {"var": 42}, + }