Skip to content

Commit 5edd968

Browse files
Ihor BilousIhor Bilous
authored andcommitted
Fix issue #24: Add batch_send method to SendingApi, add models
1 parent 247c0bc commit 5edd968

File tree

13 files changed

+490
-105
lines changed

13 files changed

+490
-105
lines changed

examples/sending.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,54 @@
3030
},
3131
)
3232

33+
batch_mail = mt.BatchSendEmailParams(
34+
base=mt.BatchMail(
35+
sender=mt.Address(email="<SENDER_EMAIL>", name="<SENDER_NAME>"),
36+
subject="You are awesome!",
37+
text="Congrats for sending test email with Mailtrap!",
38+
category="Integration Test",
39+
),
40+
requests=[
41+
mt.BatchEmailRequest(
42+
to=[mt.Address(email="<RECEIVER_EMAIL>")],
43+
),
44+
],
45+
)
46+
47+
batch_mail_from_template = mt.BatchSendEmailParams(
48+
base=mt.BatchMailFromTemplate(
49+
sender=mt.Address(email="<SENDER_EMAIL>", name="<SENDER_NAME>"),
50+
template_uuid="<YOUR_TEMPLATE_UUID>",
51+
template_variables={
52+
"company_info_name": "Test_Company_info_name",
53+
"name": "Test_Name",
54+
"company_info_address": "Test_Company_info_address",
55+
"company_info_city": "Test_Company_info_city",
56+
"company_info_zip_code": "Test_Company_info_zip_code",
57+
"company_info_country": "Test_Company_info_country",
58+
},
59+
),
60+
requests=[
61+
mt.BatchEmailRequest(
62+
to=[mt.Address(email="<RECEIVER_EMAIL>")],
63+
subject="You are awesome!",
64+
text="Congrats for sending test email with Mailtrap!",
65+
category="Integration Test",
66+
),
67+
],
68+
)
69+
3370

3471
def send(client: mt.MailtrapClient, mail: mt.BaseMail) -> mt.SEND_ENDPOINT_RESPONSE:
3572
return client.send(mail)
3673

3774

38-
def batch_send(client: mt.MailtrapClient, mail: mt.BaseMail) -> mt.SEND_ENDPOINT_RESPONSE:
39-
# will be added soon
40-
pass
75+
def batch_send(
76+
client: mt.MailtrapClient, mail: mt.BatchSendEmailParams
77+
) -> mt.BATCH_SEND_ENDPOINT_RESPONSE:
78+
return client.batch_send(mail=mail)
4179

4280

4381
if __name__ == "__main__":
4482
print(send(default_client, mail))
83+
print(batch_send(default_client, batch_mail))

mailtrap/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .client import BATCH_SEND_ENDPOINT_RESPONSE
12
from .client import SEND_ENDPOINT_RESPONSE
23
from .client import MailtrapClient
34
from .exceptions import APIError
@@ -15,6 +16,10 @@
1516
from .models.mail import Address
1617
from .models.mail import Attachment
1718
from .models.mail import BaseMail
19+
from .models.mail import BatchEmailRequest
20+
from .models.mail import BatchMail
21+
from .models.mail import BatchMailFromTemplate
22+
from .models.mail import BatchSendEmailParams
1823
from .models.mail import Disposition
1924
from .models.mail import Mail
2025
from .models.mail import MailFromTemplate

mailtrap/api/sending.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
11
from typing import Optional
22

33
from mailtrap.http import HttpClient
4-
from mailtrap.models.mail.base import BaseMail
5-
from mailtrap.models.mail.base import SendingMailResponse
4+
from mailtrap.models.mail import BaseMail
5+
from mailtrap.models.mail import SendingMailResponse
6+
from mailtrap.models.mail.batch_mail import BatchSendEmailParams
7+
from mailtrap.models.mail.batch_mail import BatchSendResponse
68

79

810
class SendingApi:
911
def __init__(self, client: HttpClient, inbox_id: Optional[str] = None) -> None:
1012
self._inbox_id = inbox_id
1113
self._client = client
1214

13-
@property
14-
def _api_url(self) -> str:
15-
url = "/api/send"
15+
def _get_api_url(self, base_url: str) -> str:
1616
if self._inbox_id:
17-
return f"{url}/{self._inbox_id}"
18-
return url
17+
return f"{base_url}/{self._inbox_id}"
18+
return base_url
1919

2020
def send(self, mail: BaseMail) -> SendingMailResponse:
2121
"""Send email (text, html, text&html, templates)."""
22-
response = self._client.post(self._api_url, json=mail.api_data)
22+
response = self._client.post(self._get_api_url("/api/send"), json=mail.api_data)
2323
return SendingMailResponse(**response)
24+
25+
def batch_send(self, mail: BatchSendEmailParams) -> BatchSendResponse:
26+
"""
27+
Batch send email (text, html, text&html, templates). Please note that
28+
the endpoint will return a 200-level http status, even when sending
29+
for individual messages may fail. Users of this endpoint should check
30+
the success and errors for each message in the response (the results
31+
are ordered the same as the original messages - requests). Please note
32+
that the endpoint accepts up to 500 messages per API call, and up to 50 MB
33+
payload size, including attachments.
34+
"""
35+
response = self._client.post(self._get_api_url("/api/batch"), json=mail.api_data)
36+
return BatchSendResponse(**response)

mailtrap/client.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
from mailtrap.exceptions import ClientConfigurationError
1818
from mailtrap.http import HttpClient
1919
from mailtrap.models.mail import BaseMail
20-
from mailtrap.models.mail.base import SendingMailResponse
20+
from mailtrap.models.mail import BatchSendResponse
21+
from mailtrap.models.mail import SendingMailResponse
22+
from mailtrap.models.mail.batch_mail import BatchSendEmailParams
2123

2224
SEND_ENDPOINT_RESPONSE = dict[str, Union[bool, list[str]]]
25+
BATCH_SEND_ENDPOINT_RESPONSE = dict[
26+
str, Union[bool, list[str], list[dict[str, Union[bool, list[str]]]]]
27+
]
2328

2429

2530
class MailtrapClient:
@@ -93,6 +98,13 @@ def send(self, mail: BaseMail) -> SEND_ENDPOINT_RESPONSE:
9398
TypeAdapter(SendingMailResponse).dump_python(sending_response),
9499
)
95100

101+
def batch_send(self, mail: BatchSendEmailParams) -> BATCH_SEND_ENDPOINT_RESPONSE:
102+
batch_sending_response = self.sending_api.batch_send(mail)
103+
return cast(
104+
BATCH_SEND_ENDPOINT_RESPONSE,
105+
TypeAdapter(BatchSendResponse).dump_python(batch_sending_response),
106+
)
107+
96108
@property
97109
def base_url(self) -> str:
98110
warnings.warn(

mailtrap/models/mail/__init__.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
from mailtrap.models.mail.address import Address
22
from mailtrap.models.mail.attachment import Attachment
33
from mailtrap.models.mail.attachment import Disposition
4-
from mailtrap.models.mail.base import BaseMail
5-
from mailtrap.models.mail.from_template import MailFromTemplate
4+
from mailtrap.models.mail.batch_mail import BaseBatchMail
5+
from mailtrap.models.mail.batch_mail import BatchEmailRequest
6+
from mailtrap.models.mail.batch_mail import BatchMail
7+
from mailtrap.models.mail.batch_mail import BatchMailFromTemplate
8+
from mailtrap.models.mail.batch_mail import BatchSendEmailParams
9+
from mailtrap.models.mail.batch_mail import BatchSendResponse
10+
from mailtrap.models.mail.mail import BaseMail
611
from mailtrap.models.mail.mail import Mail
12+
from mailtrap.models.mail.mail import MailFromTemplate
13+
from mailtrap.models.mail.mail import SendingMailResponse
714

815
__all__ = [
916
"Address",
1017
"Attachment",
11-
"Disposition",
18+
"BaseBatchMail",
1219
"BaseMail",
20+
"BatchEmailRequest",
21+
"BatchMail",
22+
"BatchMailFromTemplate",
23+
"BatchSendEmailParams",
24+
"BatchSendResponse",
25+
"Disposition",
1326
"Mail",
1427
"MailFromTemplate",
28+
"SendingMailResponse",
1529
]

mailtrap/models/mail/base.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

mailtrap/models/mail/batch_mail.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from typing import Any
2+
from typing import Optional
3+
from typing import Union
4+
5+
from pydantic import Field
6+
from pydantic.dataclasses import dataclass
7+
8+
from mailtrap.models.common import RequestParams
9+
from mailtrap.models.mail.address import Address
10+
from mailtrap.models.mail.attachment import Attachment
11+
12+
13+
@dataclass
14+
class BaseBatchMail(RequestParams):
15+
sender: Address = Field(..., serialization_alias="from")
16+
attachments: Optional[list[Attachment]] = None
17+
headers: Optional[dict[str, str]] = None
18+
custom_variables: Optional[dict[str, Any]] = None
19+
reply_to: Optional[Address] = None
20+
21+
22+
@dataclass
23+
class BatchMail(BaseBatchMail):
24+
subject: str = Field(...) # type:ignore
25+
text: Optional[str] = None
26+
html: Optional[str] = None
27+
category: Optional[str] = None
28+
29+
30+
@dataclass
31+
class BatchMailFromTemplate(BaseBatchMail):
32+
template_uuid: str = Field(...) # type:ignore
33+
template_variables: Optional[dict[str, Any]] = None
34+
35+
36+
@dataclass
37+
class BatchEmailRequest(BaseBatchMail):
38+
to: list[Address] = Field(...) # type:ignore
39+
sender: Optional[Address] = Field(
40+
None, serialization_alias="from"
41+
) # type: ignore[assignment]
42+
cc: Optional[list[Address]] = None
43+
bcc: Optional[list[Address]] = None
44+
subject: Optional[str] = None
45+
text: Optional[str] = None
46+
html: Optional[str] = None
47+
category: Optional[str] = None
48+
template_uuid: Optional[str] = None
49+
template_variables: Optional[dict[str, Any]] = None
50+
51+
52+
@dataclass
53+
class BatchSendEmailParams(RequestParams):
54+
base: Union[BatchMail, BatchMailFromTemplate]
55+
requests: list[BatchEmailRequest]
56+
57+
58+
@dataclass
59+
class BatchSendResponseItem:
60+
success: bool
61+
message_ids: Optional[list[str]] = None
62+
errors: Optional[list[str]] = None
63+
64+
65+
@dataclass
66+
class BatchSendResponse:
67+
success: bool
68+
responses: list[BatchSendResponseItem]
69+
errors: Optional[list[str]] = None

mailtrap/models/mail/from_template.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

mailtrap/models/mail/mail.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1+
from typing import Any
12
from typing import Optional
23

34
from pydantic import Field
45
from pydantic.dataclasses import dataclass
56

6-
from mailtrap.models.mail.base import BaseMail
7+
from mailtrap.models.common import RequestParams
8+
from mailtrap.models.mail.address import Address
9+
from mailtrap.models.mail.attachment import Attachment
10+
11+
12+
@dataclass
13+
class BaseMail(RequestParams):
14+
to: list[Address]
15+
sender: Address = Field(..., serialization_alias="from")
16+
cc: Optional[list[Address]] = None
17+
bcc: Optional[list[Address]] = None
18+
attachments: Optional[list[Attachment]] = None
19+
headers: Optional[dict[str, str]] = None
20+
custom_variables: Optional[dict[str, Any]] = None
21+
reply_to: Optional[Address] = None
722

823

924
@dataclass
@@ -12,3 +27,15 @@ class Mail(BaseMail):
1227
text: Optional[str] = None
1328
html: Optional[str] = None
1429
category: Optional[str] = None
30+
31+
32+
@dataclass
33+
class MailFromTemplate(BaseMail):
34+
template_uuid: str = Field(...) # type:ignore
35+
template_variables: Optional[dict[str, Any]] = None
36+
37+
38+
@dataclass
39+
class SendingMailResponse:
40+
success: bool
41+
message_ids: list[str]

0 commit comments

Comments
 (0)