Skip to content

Commit c4a1e5e

Browse files
committed
Add Stats API
1 parent f0f6a05 commit c4a1e5e

6 files changed

Lines changed: 61 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
## [2.5.0] - 2026-03-06
2+
3+
- Add StatsApi with get, by_domains, by_categories, by_email_service_providers, by_date endpoints
4+
- Add api_query_params to RequestParams for automatic [] serialization of list query params
5+
16
## [2.4.0] - 2025-12-04
2-
* Fix issue #52: Update README.md using new guideline by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/55
3-
* Fix issue #53: Add full usage in all examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/56
4-
* Merge functionality and examples in Readme by @yanchuk in https://github.com/mailtrap/mailtrap-python/pull/57
5-
* Fix issue #54: Add SendingDomainsApi, related models, tests, examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/58
7+
8+
- Fix issue #52: Update README.md using new guideline by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/55
9+
- Fix issue #53: Add full usage in all examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/56
10+
- Merge functionality and examples in Readme by @yanchuk in https://github.com/mailtrap/mailtrap-python/pull/57
11+
- Fix issue #54: Add SendingDomainsApi, related models, tests, examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/58
612

713
## [2.3.0] - 2025-10-24
8-
* Fix issue #24: Add batch_send method to SendingApi, add models by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/47
9-
* Fix issue #42: Add GeneralApi, related models, examples, tests. by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/48
10-
* Fix issue #41: Add ContactExportsApi, related models, tests and examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/49
11-
* Fix issue #45: Add ContactEventsApi, related models, tests and examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/51
14+
15+
- Fix issue #24: Add batch_send method to SendingApi, add models by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/47
16+
- Fix issue #42: Add GeneralApi, related models, examples, tests. by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/48
17+
- Fix issue #41: Add ContactExportsApi, related models, tests and examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/49
18+
- Fix issue #45: Add ContactEventsApi, related models, tests and examples by @Ihor-Bilous in https://github.com/mailtrap/mailtrap-python/pull/51
1219

1320
## [2.2.0] - 2025-09-18
21+
1422
- Potential fix for code scanning alert no. 1: Workflow does not contain permissions by @mklocek in https://github.com/railsware/mailtrap-python/pull/15
1523
- Fix issue #29. Add support of Emails Sandbox (Testing) API: Projects by @Ihor-Bilous in https://github.com/railsware/mailtrap-python/pull/31
1624
- Issue 25 by @Ihor-Bilous in https://github.com/railsware/mailtrap-python/pull/33
@@ -25,13 +33,15 @@
2533
- Fix issue #28: Add AttachmentsApi, related models, tests, examples by @Ihor-Bilous in https://github.com/railsware/mailtrap-python/pull/44
2634

2735
## [2.1.0] - 2025-05-12
36+
2837
- Add sandbox mode support in MailtrapClient
2938
- It requires inbox_id parameter to be set
3039
- Add bulk mode support in MailtrapClient
3140
- Drop support python 3.6 - 3.8
3241
- Add support for python 3.12 - 3.13
3342

3443
## [2.0.1] - 2023-05-18
44+
3545
- Add User-Agent header to all requests
3646

3747
## [2.0.0] - 2023-03-11

examples/general/stats.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import mailtrap as mt
2-
from mailtrap.models.stats import SendingStatGroup
3-
from mailtrap.models.stats import SendingStats
4-
from mailtrap.models.stats import StatsFilterParams
2+
from mailtrap.models.stats import SendingStatGroup, SendingStats, StatsFilterParams
53

64
API_TOKEN = "YOUR_API_TOKEN"
7-
ACCOUNT_ID = "YOUR_ACCOUNT_ID"
5+
ACCOUNT_ID = 123456
86

97
client = mt.MailtrapClient(token=API_TOKEN)
108
stats_api = client.general_api.stats
@@ -41,7 +39,7 @@ def get_stats_with_filters(account_id: int) -> SendingStats:
4139
end_date="2026-01-31",
4240
sending_domain_ids=[1, 2],
4341
sending_streams=["transactional"],
44-
categories=["Transactional", "Marketing"],
42+
categories=["Welcome email", "Marketing"],
4543
email_service_providers=["Gmail", "Yahoo"],
4644
)
4745
return stats_api.get(account_id=account_id, params=params)
@@ -52,7 +50,7 @@ def get_stats_by_domains_with_filters(account_id: int) -> list[SendingStatGroup]
5250
start_date="2026-01-01",
5351
end_date="2026-01-31",
5452
sending_streams=["transactional"],
55-
categories=["Transactional"],
53+
categories=["Welcome email"],
5654
)
5755
return stats_api.by_domains(account_id=account_id, params=params)
5856

mailtrap/api/resources/stats.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from typing import Literal
2+
13
from mailtrap.http import HttpClient
2-
from mailtrap.models.stats import SendingStatGroup
3-
from mailtrap.models.stats import SendingStats
4-
from mailtrap.models.stats import StatsFilterParams
4+
from mailtrap.models.stats import SendingStatGroup, SendingStats, StatsFilterParams
5+
6+
GroupKey = Literal["domains", "categories", "email_service_providers", "date"]
57

6-
GROUP_KEYS = {
8+
_GROUP_KEYS = {
79
"domains": "sending_domain_id",
810
"categories": "category",
911
"email_service_providers": "email_service_provider",
@@ -17,14 +19,21 @@ def __init__(self, client: HttpClient) -> None:
1719

1820
def get(self, account_id: int, params: StatsFilterParams) -> SendingStats:
1921
"""Get aggregated sending stats."""
20-
response = self._client.get(self._base_path(account_id), params=params.api_query_params)
22+
response = self._client.get(
23+
self._base_path(account_id),
24+
params=params.api_query_params,
25+
)
2126
return SendingStats(**response)
2227

23-
def by_domains(self, account_id: int, params: StatsFilterParams) -> list[SendingStatGroup]:
28+
def by_domains(
29+
self, account_id: int, params: StatsFilterParams
30+
) -> list[SendingStatGroup]:
2431
"""Get sending stats grouped by domains."""
2532
return self._grouped_stats(account_id, "domains", params)
2633

27-
def by_categories(self, account_id: int, params: StatsFilterParams) -> list[SendingStatGroup]:
34+
def by_categories(
35+
self, account_id: int, params: StatsFilterParams
36+
) -> list[SendingStatGroup]:
2837
"""Get sending stats grouped by categories."""
2938
return self._grouped_stats(account_id, "categories", params)
3039

@@ -34,17 +43,19 @@ def by_email_service_providers(
3443
"""Get sending stats grouped by email service providers."""
3544
return self._grouped_stats(account_id, "email_service_providers", params)
3645

37-
def by_date(self, account_id: int, params: StatsFilterParams) -> list[SendingStatGroup]:
46+
def by_date(
47+
self, account_id: int, params: StatsFilterParams
48+
) -> list[SendingStatGroup]:
3849
"""Get sending stats grouped by date."""
3950
return self._grouped_stats(account_id, "date", params)
4051

4152
def _grouped_stats(
42-
self, account_id: int, group: str, params: StatsFilterParams
53+
self, account_id: int, group: GroupKey, params: StatsFilterParams
4354
) -> list[SendingStatGroup]:
4455
response = self._client.get(
4556
f"{self._base_path(account_id)}/{group}", params=params.api_query_params
4657
)
47-
group_key = GROUP_KEYS[group]
58+
group_key = _GROUP_KEYS[group]
4859

4960
return [
5061
SendingStatGroup(

mailtrap/models/stats.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ class SendingStatGroup:
2929

3030
@dataclass
3131
class StatsFilterParams(RequestParams):
32-
start_date: str = ""
33-
end_date: str = ""
34-
sending_domain_ids: Optional[list] = None
35-
sending_streams: Optional[list] = None
36-
categories: Optional[list] = None
37-
email_service_providers: Optional[list] = None
32+
start_date: Optional[str] = None
33+
end_date: Optional[str] = None
34+
sending_domain_ids: Optional[list[int]] = None
35+
sending_streams: Optional[list[str]] = None
36+
categories: Optional[list[str]] = None
37+
email_service_providers: Optional[list[str]] = None

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mailtrap"
3-
version = "2.4.0"
3+
version = "2.5.0"
44
description = "Official mailtrap.io API client"
55
readme = "README.md"
66
license = {file = "LICENSE.txt"}
@@ -23,7 +23,7 @@ dynamic = ["dependencies"]
2323
Homepage = "https://mailtrap.io/"
2424
Documentation = "https://github.com/railsware/mailtrap-python"
2525
Repository = "https://github.com/railsware/mailtrap-python.git"
26-
"API documentation" = "https://api-docs.mailtrap.io/"
26+
"API documentation" = "https://docs.mailtrap.io/developers"
2727

2828
[build-system]
2929
requires = ["setuptools"]

tests/unit/api/general/test_stats.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ def test_get_should_return_sending_stats(
143143
assert stats.spam_rate == 0.013
144144

145145
@responses.activate
146-
def test_get_with_filter_params(self, client: StatsApi, sample_stats_dict: dict) -> None:
146+
def test_get_with_filter_params(
147+
self, client: StatsApi, sample_stats_dict: dict
148+
) -> None:
147149
responses.get(
148150
BASE_STATS_URL,
149151
json=sample_stats_dict,
@@ -155,16 +157,16 @@ def test_get_with_filter_params(self, client: StatsApi, sample_stats_dict: dict)
155157
end_date="2026-01-31",
156158
sending_domain_ids=[1, 2],
157159
sending_streams=["transactional"],
158-
categories=["Transactional"],
160+
categories=["Welcome email"],
159161
email_service_providers=["Gmail"],
160162
)
161163
client.get(ACCOUNT_ID, params)
162164

163165
request_params = responses.calls[0].request.params
164-
assert "sending_domain_ids[]" in request_params
165-
assert "sending_streams[]" in request_params
166-
assert "categories[]" in request_params
167-
assert "email_service_providers[]" in request_params
166+
assert request_params["sending_domain_ids[]"] == ["1", "2"]
167+
assert request_params["sending_streams[]"] == "transactional"
168+
assert request_params["categories[]"] == "Welcome email"
169+
assert request_params["email_service_providers[]"] == "Gmail"
168170

169171
@responses.activate
170172
def test_by_domains_should_return_grouped_stats(
@@ -192,7 +194,7 @@ def test_by_domains_should_return_grouped_stats(
192194
def test_by_categories_should_return_grouped_stats(self, client: StatsApi) -> None:
193195
response_data = [
194196
{
195-
"category": "Transactional",
197+
"category": "Welcome email",
196198
"stats": {
197199
"delivery_count": 100,
198200
"delivery_rate": 0.97,
@@ -217,7 +219,7 @@ def test_by_categories_should_return_grouped_stats(self, client: StatsApi) -> No
217219

218220
assert len(result) == 1
219221
assert result[0].name == "category"
220-
assert result[0].value == "Transactional"
222+
assert result[0].value == "Welcome email"
221223
assert result[0].stats.delivery_count == 100
222224

223225
@responses.activate

0 commit comments

Comments
 (0)