lettermint 2.2.0__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {lettermint-2.2.0 → lettermint-2.3.0}/PKG-INFO +1 -1
  2. {lettermint-2.2.0 → lettermint-2.3.0}/pyproject.toml +1 -1
  3. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/__init__.py +1 -1
  4. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/endpoints/email.py +10 -0
  5. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/types.py +27 -25
  6. {lettermint-2.2.0 → lettermint-2.3.0}/tests/test_email.py +4 -3
  7. {lettermint-2.2.0 → lettermint-2.3.0}/.github/dependabot.yml +0 -0
  8. {lettermint-2.2.0 → lettermint-2.3.0}/.github/workflows/ci.yml +0 -0
  9. {lettermint-2.2.0 → lettermint-2.3.0}/.github/workflows/fix-code-style.yml +0 -0
  10. {lettermint-2.2.0 → lettermint-2.3.0}/.github/workflows/release-to-discord.yml +0 -0
  11. {lettermint-2.2.0 → lettermint-2.3.0}/.github/workflows/release.yml +0 -0
  12. {lettermint-2.2.0 → lettermint-2.3.0}/.github/workflows/update-changelog.yml +0 -0
  13. {lettermint-2.2.0 → lettermint-2.3.0}/.gitignore +0 -0
  14. {lettermint-2.2.0 → lettermint-2.3.0}/CHANGELOG.md +0 -0
  15. {lettermint-2.2.0 → lettermint-2.3.0}/LICENSE +0 -0
  16. {lettermint-2.2.0 → lettermint-2.3.0}/README.md +0 -0
  17. {lettermint-2.2.0 → lettermint-2.3.0}/UPGRADE.md +0 -0
  18. {lettermint-2.2.0 → lettermint-2.3.0}/examples/async_send.py +0 -0
  19. {lettermint-2.2.0 → lettermint-2.3.0}/examples/basic_send.py +0 -0
  20. {lettermint-2.2.0 → lettermint-2.3.0}/examples/webhook_verification.py +0 -0
  21. {lettermint-2.2.0 → lettermint-2.3.0}/examples/with_attachments.py +0 -0
  22. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/client.py +0 -0
  23. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/endpoints/__init__.py +0 -0
  24. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/endpoints/api.py +0 -0
  25. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/endpoints/endpoint.py +0 -0
  26. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/exceptions.py +0 -0
  27. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/lettermint.py +0 -0
  28. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/py.typed +0 -0
  29. {lettermint-2.2.0 → lettermint-2.3.0}/src/lettermint/webhook.py +0 -0
  30. {lettermint-2.2.0 → lettermint-2.3.0}/tests/__init__.py +0 -0
  31. {lettermint-2.2.0 → lettermint-2.3.0}/tests/conftest.py +0 -0
  32. {lettermint-2.2.0 → lettermint-2.3.0}/tests/test_api_surface.py +0 -0
  33. {lettermint-2.2.0 → lettermint-2.3.0}/tests/test_client.py +0 -0
  34. {lettermint-2.2.0 → lettermint-2.3.0}/tests/test_webhook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lettermint
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Official Lettermint Python SDK
5
5
  Project-URL: Homepage, https://github.com/lettermint/lettermint-python
6
6
  Project-URL: Documentation, https://github.com/lettermint/lettermint-python#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lettermint"
7
- version = "2.2.0"
7
+ version = "2.3.0"
8
8
  description = "Official Lettermint Python SDK"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -60,7 +60,7 @@ from .types import (
60
60
  )
61
61
  from .webhook import Webhook
62
62
 
63
- __version__ = "2.2.0"
63
+ __version__ = "2.3.0"
64
64
 
65
65
  __all__ = [
66
66
  # Main clients
@@ -276,6 +276,11 @@ class EmailEndpoint(Endpoint):
276
276
  self._payload["tag"] = tag
277
277
  return self
278
278
 
279
+ def tags(self, tags: list[dict[str, str]]) -> Self:
280
+ """Set reusable name-value tags for the email."""
281
+ self._payload["tags"] = tags
282
+ return self
283
+
279
284
  def send(self) -> SendEmailResponse:
280
285
  """Send the composed email.
281
286
 
@@ -555,6 +560,11 @@ class AsyncEmailEndpoint(AsyncEndpoint):
555
560
  self._payload["tag"] = tag
556
561
  return self
557
562
 
563
+ def tags(self, tags: list[dict[str, str]]) -> Self:
564
+ """Set reusable name-value tags for the email."""
565
+ self._payload["tags"] = tags
566
+ return self
567
+
558
568
  def send(self) -> Coroutine[Any, Any, SendEmailResponse]:
559
569
  """Send the composed email asynchronously.
560
570
 
@@ -36,6 +36,7 @@ SendMailRequest = TypedDict(
36
36
  "headers": "NotRequired[dict[str, str]]",
37
37
  "metadata": "NotRequired[dict[str, str]]",
38
38
  "tag": "NotRequired[str | None]",
39
+ "tags": "NotRequired[list[dict[str, Any]]]",
39
40
  "settings": "NotRequired[dict[str, Any] | None]",
40
41
  "html": "NotRequired[str | None]",
41
42
  "text": "NotRequired[str | None]",
@@ -43,7 +44,7 @@ SendMailRequest = TypedDict(
43
44
  },
44
45
  )
45
46
 
46
- SendBatchMailRequest: TypeAlias = list[SendMailRequest]
47
+ SendBatchMailRequest: TypeAlias = list[dict[str, Any]]
47
48
  AttachmentDelivery: TypeAlias = Literal["inline", "url"]
48
49
  BuiltInTeamRole: TypeAlias = Literal["owner", "admin", "member"]
49
50
  CursorPaginator = TypedDict(
@@ -150,6 +151,7 @@ MessageData = TypedDict(
150
151
  "status": "Required[MessageStatus]",
151
152
  "status_changed_at": "Required[str | None]",
152
153
  "tag": "Required[str | None]",
154
+ "tags": "Required[list[dict[str, Any]]]",
153
155
  "from_email": "Required[str]",
154
156
  "from_name": "Required[str | None]",
155
157
  "reply_to": "Required[list[str] | None]",
@@ -192,6 +194,8 @@ MessageEventData = TypedDict(
192
194
  {
193
195
  "message_id": "Required[str]",
194
196
  "event": "Required[MessageEventType]",
197
+ "tag": "Required[str | None]",
198
+ "tags": "Required[list[dict[str, Any]]]",
195
199
  "metadata": "Required[dict[str, Any] | None]",
196
200
  "timestamp": "Required[str]",
197
201
  },
@@ -212,6 +216,7 @@ MessageListData = TypedDict(
212
216
  "bcc": "Required[list[MessageRecipientData] | None]",
213
217
  "reply_to": "Required[list[str] | None]",
214
218
  "tag": "Required[str | None]",
219
+ "tags": "Required[list[dict[str, Any]]]",
215
220
  "status_changed_at": "Required[str | None]",
216
221
  "created_at": "Required[str]",
217
222
  },
@@ -229,7 +234,6 @@ MessageStatsData = TypedDict(
229
234
 
230
235
  Plan: TypeAlias = Literal["free", "starter", "growth", "pro"]
231
236
  ProjectAccessScope: TypeAlias = Literal["all", "selected"]
232
- RouteType: TypeAlias = Literal["transactional", "broadcast", "inbound"]
233
237
  RouteStatisticData = TypedDict(
234
238
  "RouteStatisticData",
235
239
  {
@@ -250,6 +254,7 @@ RouteStatisticData = TypedDict(
250
254
  },
251
255
  )
252
256
 
257
+ RouteType: TypeAlias = Literal["transactional", "broadcast", "inbound"]
253
258
  RouteData = TypedDict(
254
259
  "RouteData",
255
260
  {
@@ -373,6 +378,13 @@ RouteListData = TypedDict(
373
378
  },
374
379
  )
375
380
 
381
+ StatsInboundData = TypedDict(
382
+ "StatsInboundData",
383
+ {
384
+ "received": "Required[int]",
385
+ },
386
+ )
387
+
376
388
  StatsTypeData = TypedDict(
377
389
  "StatsTypeData",
378
390
  {
@@ -382,13 +394,6 @@ StatsTypeData = TypedDict(
382
394
  },
383
395
  )
384
396
 
385
- StatsInboundData = TypedDict(
386
- "StatsInboundData",
387
- {
388
- "received": "Required[int]",
389
- },
390
- )
391
-
392
397
  StatsDailyData = TypedDict(
393
398
  "StatsDailyData",
394
399
  {
@@ -478,8 +483,8 @@ StoreRouteData = TypedDict(
478
483
  },
479
484
  )
480
485
 
481
- SuppressionScope: TypeAlias = Literal["global", "team", "project", "route"]
482
486
  SuppressionReason: TypeAlias = Literal["spam_complaint", "hard_bounce", "unsubscribe", "manual"]
487
+ SuppressionScope: TypeAlias = Literal["global", "team", "project", "route"]
483
488
  StoreSuppressionData = TypedDict(
484
489
  "StoreSuppressionData",
485
490
  {
@@ -644,6 +649,15 @@ UpdateProjectData = TypedDict(
644
649
  },
645
650
  )
646
651
 
652
+ UpdateRouteInboundSettingsData = TypedDict(
653
+ "UpdateRouteInboundSettingsData",
654
+ {
655
+ "inbound_domain": "NotRequired[str | None]",
656
+ "inbound_spam_threshold": "NotRequired[float | None]",
657
+ "attachment_delivery": "NotRequired[AttachmentDelivery | None]",
658
+ },
659
+ )
660
+
647
661
  UpdateRouteSettingsData = TypedDict(
648
662
  "UpdateRouteSettingsData",
649
663
  {
@@ -651,21 +665,13 @@ UpdateRouteSettingsData = TypedDict(
651
665
  "track_clicks": "NotRequired[bool | None]",
652
666
  "generate_plaintext_fallback": "NotRequired[bool | None]",
653
667
  "suppress_auto_responders": "NotRequired[bool | None]",
668
+ "suppress_disposable_recipients": "NotRequired[bool | None]",
654
669
  "tls": "NotRequired[TlsPolicy | None]",
655
670
  "disable_hosted_unsubscribe": "NotRequired[bool | None]",
656
671
  "redact_email_content": "NotRequired[bool | None]",
657
672
  },
658
673
  )
659
674
 
660
- UpdateRouteInboundSettingsData = TypedDict(
661
- "UpdateRouteInboundSettingsData",
662
- {
663
- "inbound_domain": "NotRequired[str | None]",
664
- "inbound_spam_threshold": "NotRequired[float | None]",
665
- "attachment_delivery": "NotRequired[AttachmentDelivery | None]",
666
- },
667
- )
668
-
669
675
  UpdateRouteData = TypedDict(
670
676
  "UpdateRouteData",
671
677
  {
@@ -860,12 +866,8 @@ MessageEventsResponse = TypedDict(
860
866
  "MessageEventsResponse",
861
867
  {
862
868
  "data": "Required[list[MessageEventData]]",
863
- "path": "Required[str | None]",
864
- "per_page": "Required[int]",
865
- "next_cursor": "Required[str | None]",
866
- "next_page_url": "Required[str | None]",
867
- "prev_cursor": "Required[str | None]",
868
- "prev_page_url": "Required[str | None]",
869
+ "links": "Required[list[str]]",
870
+ "meta": "Required[dict[str, Any]]",
869
871
  },
870
872
  )
871
873
 
@@ -186,15 +186,16 @@ class TestEmailEndpointSync:
186
186
  with Lettermint(api_token=api_token) as client:
187
187
  client.email.from_("sender@example.com").to("recipient@example.com").subject(
188
188
  "Test"
189
- ).metadata({"campaign_id": "123"}).tag("welcome").settings(
190
- {"track_opens": False, "track_clicks": True, "tls": "enforced"}
191
- ).send()
189
+ ).metadata({"campaign_id": "123"}).tag("welcome").tags(
190
+ [{"name": "campaign", "value": "welcome-v2"}]
191
+ ).settings({"track_opens": False, "track_clicks": True, "tls": "enforced"}).send()
192
192
 
193
193
  import json
194
194
 
195
195
  body = json.loads(route.calls.last.request.content)
196
196
  assert body["metadata"] == {"campaign_id": "123"}
197
197
  assert body["tag"] == "welcome"
198
+ assert body["tags"] == [{"name": "campaign", "value": "welcome-v2"}]
198
199
  assert body["settings"] == {
199
200
  "track_opens": False,
200
201
  "track_clicks": True,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes