Skip to content

Commit d139f84

Browse files
authored
Fix issue #18: Add api for EmailTemplates, add tests and examples (#34)
* Fix issue #18: Add api for EmailTemplates, add tests and examples
1 parent 398ed79 commit d139f84

File tree

18 files changed

+582
-8
lines changed

18 files changed

+582
-8
lines changed

examples/email_templates/templates.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from typing import Optional
2+
3+
import mailtrap as mt
4+
from mailtrap.models.common import DeletedObject
5+
from mailtrap.models.templates import EmailTemplate
6+
7+
API_TOKEN = "YOU_API_TOKEN"
8+
ACCOUNT_ID = "YOU_ACCOUNT_ID"
9+
10+
client = mt.MailtrapClient(token=API_TOKEN, account_id=ACCOUNT_ID)
11+
templates_api = client.email_templates_api.templates
12+
13+
14+
def list_templates() -> list[EmailTemplate]:
15+
return templates_api.get_list()
16+
17+
18+
def create_template(
19+
name: str,
20+
subject: str,
21+
category: str,
22+
body_text: Optional[str] = None,
23+
body_html: Optional[str] = None,
24+
) -> EmailTemplate:
25+
params = mt.CreateEmailTemplateParams(
26+
name=name,
27+
subject=subject,
28+
category=category,
29+
body_text=body_text,
30+
body_html=body_html,
31+
)
32+
return templates_api.create(params)
33+
34+
35+
def get_template(template_id: str) -> EmailTemplate:
36+
return templates_api.get_by_id(template_id)
37+
38+
39+
def update_template(
40+
template_id: str,
41+
name: Optional[str] = None,
42+
subject: Optional[str] = None,
43+
category: Optional[str] = None,
44+
body_text: Optional[str] = None,
45+
body_html: Optional[str] = None,
46+
) -> EmailTemplate:
47+
params = mt.UpdateEmailTemplateParams(
48+
name=name,
49+
subject=subject,
50+
category=category,
51+
body_text=body_text,
52+
body_html=body_html,
53+
)
54+
return templates_api.update(template_id, params)
55+
56+
57+
def delete_template(template_id: str) -> DeletedObject:
58+
return templates_api.delete(template_id)
59+
60+
61+
if __name__ == "__main__":
62+
print(list_templates())

mailtrap/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010
from .models.mail import Disposition
1111
from .models.mail import Mail
1212
from .models.mail import MailFromTemplate
13+
from .models.templates import CreateEmailTemplateParams
14+
from .models.templates import UpdateEmailTemplateParams

mailtrap/api/resources/templates.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from mailtrap.http import HttpClient
2+
from mailtrap.models.common import DeletedObject
3+
from mailtrap.models.templates import CreateEmailTemplateParams
4+
from mailtrap.models.templates import EmailTemplate
5+
from mailtrap.models.templates import UpdateEmailTemplateParams
6+
7+
8+
class TemplatesApi:
9+
def __init__(self, client: HttpClient, account_id: str) -> None:
10+
self._account_id = account_id
11+
self._client = client
12+
13+
def get_list(self) -> list[EmailTemplate]:
14+
response = self._client.get(f"/api/accounts/{self._account_id}/email_templates")
15+
return [EmailTemplate(**template) for template in response]
16+
17+
def get_by_id(self, template_id: int) -> EmailTemplate:
18+
response = self._client.get(
19+
f"/api/accounts/{self._account_id}/email_templates/{template_id}"
20+
)
21+
return EmailTemplate(**response)
22+
23+
def create(self, template_params: CreateEmailTemplateParams) -> EmailTemplate:
24+
response = self._client.post(
25+
f"/api/accounts/{self._account_id}/email_templates",
26+
json={"email_template": template_params.api_data},
27+
)
28+
return EmailTemplate(**response)
29+
30+
def update(
31+
self, template_id: int, template_params: UpdateEmailTemplateParams
32+
) -> EmailTemplate:
33+
response = self._client.patch(
34+
f"/api/accounts/{self._account_id}/email_templates/{template_id}",
35+
json={"email_template": template_params.api_data},
36+
)
37+
return EmailTemplate(**response)
38+
39+
def delete(self, template_id: int) -> DeletedObject:
40+
self._client.delete(
41+
f"/api/accounts/{self._account_id}/email_templates/{template_id}"
42+
)
43+
return DeletedObject(template_id)

mailtrap/api/templates.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from mailtrap.api.resources.templates import TemplatesApi
2+
from mailtrap.http import HttpClient
3+
4+
5+
class EmailTemplatesApi:
6+
def __init__(self, client: HttpClient, account_id: str) -> None:
7+
self._account_id = account_id
8+
self._client = client
9+
10+
@property
11+
def templates(self) -> TemplatesApi:
12+
return TemplatesApi(account_id=self._account_id, client=self._client)

mailtrap/client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pydantic import TypeAdapter
77

88
from mailtrap.api.sending import SendingApi
9+
from mailtrap.api.templates import EmailTemplatesApi
910
from mailtrap.api.testing import TestingApi
1011
from mailtrap.config import BULK_HOST
1112
from mailtrap.config import GENERAL_HOST
@@ -54,6 +55,14 @@ def testing_api(self) -> TestingApi:
5455
client=HttpClient(host=GENERAL_HOST, headers=self.headers),
5556
)
5657

58+
@property
59+
def email_templates_api(self) -> EmailTemplatesApi:
60+
self._validate_account_id()
61+
return EmailTemplatesApi(
62+
account_id=cast(str, self.account_id),
63+
client=HttpClient(host=GENERAL_HOST, headers=self.headers),
64+
)
65+
5766
@property
5867
def sending_api(self) -> SendingApi:
5968
http_client = HttpClient(host=self._sending_api_host, headers=self.headers)

mailtrap/http.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ def _url(self, path: str) -> str:
5050
def _process_response(self, response: Response) -> Any:
5151
if not response.ok:
5252
self._handle_failed_response(response)
53+
54+
if not response.content.strip():
55+
return None
56+
5357
return response.json()
5458

5559
def _handle_failed_response(self, response: Response) -> NoReturn:

mailtrap/models/common.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
from pydantic import TypeAdapter
66
from pydantic.dataclasses import dataclass
77

8-
T = TypeVar("T", bound="RequestModel")
8+
T = TypeVar("T", bound="RequestParams")
99

1010

1111
@dataclass
12-
class RequestModel:
12+
class RequestParams:
1313
@property
1414
def api_data(self: T) -> dict[str, Any]:
1515
return cast(

mailtrap/models/mail/address.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
from pydantic.dataclasses import dataclass
44

5-
from mailtrap.models.common import RequestModel
5+
from mailtrap.models.common import RequestParams
66

77

88
@dataclass
9-
class Address(RequestModel):
9+
class Address(RequestParams):
1010
email: str
1111
name: Optional[str] = None

mailtrap/models/mail/attachment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pydantic import field_serializer
77
from pydantic.dataclasses import dataclass
88

9-
from mailtrap.models.common import RequestModel
9+
from mailtrap.models.common import RequestParams
1010

1111

1212
class Disposition(str, Enum):
@@ -15,7 +15,7 @@ class Disposition(str, Enum):
1515

1616

1717
@dataclass
18-
class Attachment(RequestModel):
18+
class Attachment(RequestParams):
1919
content: bytes
2020
filename: str
2121
disposition: Optional[Disposition] = None

mailtrap/models/mail/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
from pydantic import Field
55
from pydantic.dataclasses import dataclass
66

7-
from mailtrap.models.common import RequestModel
7+
from mailtrap.models.common import RequestParams
88
from mailtrap.models.mail.address import Address
99
from mailtrap.models.mail.attachment import Attachment
1010

1111

1212
@dataclass
13-
class BaseMail(RequestModel):
13+
class BaseMail(RequestParams):
1414
sender: Address = Field(..., serialization_alias="from")
1515
to: list[Address] = Field(...)
1616
cc: Optional[list[Address]] = None

0 commit comments

Comments
 (0)