sendly-python 1.2.0__tar.gz → 1.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.
- {sendly_python-1.2.0 → sendly_python-1.3.0}/CHANGELOG.md +21 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/PKG-INFO +21 -1
- {sendly_python-1.2.0 → sendly_python-1.3.0}/README.md +20 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/pyproject.toml +1 -1
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/client.py +1 -1
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/types.py +5 -1
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/fixtures/openapi.json +19835 -5361
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_contract.py +137 -3
- {sendly_python-1.2.0 → sendly_python-1.3.0}/.github/workflows/ci.yml +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/.github/workflows/release.yml +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/.gitignore +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/LICENSE +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/scripts/sync_spec.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/__init__.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/errors.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/py.typed +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/__init__.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/_helpers.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/_pagination.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/analytics.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/campaigns.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/contacts.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/deliverability.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/domains.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/emails.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/events.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/lists.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/mailboxes.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/projects.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/segments.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/snippets.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/suppression.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/templates.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/topics.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/usage.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/validation.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/verify.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/webhooks.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/resources/workflows.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/src/sendly/webhook_utils.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/support.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_analytics.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_campaigns.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_client.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_contacts.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_deliverability.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_domain_logo.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_domains.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_emails.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_errors_problem.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_events.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_lists.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_mailbox_conversations.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_mailboxes.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_projects.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_segments.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_snippets.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_suppression.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_templates.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_topics.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_usage.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_validation.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_verify.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_webhook_verify.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_webhooks.py +0 -0
- {sendly_python-1.2.0 → sendly_python-1.3.0}/tests/test_workflows.py +0 -0
|
@@ -5,6 +5,27 @@ All notable changes to `sendly-python` are documented here. This project adheres
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.3.0] - 2026-11-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Why a message bounced or was complained about.** An email (`emails.get`, `emails.list`)
|
|
13
|
+
gains the keys `bounceType`, `bounceSubType`, `bounceStatusCode`, `bounceDiagnosticCode` and
|
|
14
|
+
`complaintFeedbackType`; each entry of its delivery history gains the four `bounce*` keys. The
|
|
15
|
+
`email.bounced` webhook body gains `bounceSubType`, `bounceStatusCode` and
|
|
16
|
+
`bounceDiagnosticCode`, and `email.complained` gains `complaintFeedbackType`. All are `str | None`
|
|
17
|
+
and additive: responses are plain dicts, so existing code is unaffected.
|
|
18
|
+
- **Three other optional fields arrive with the re-sync:** `Email.hold`, `Problem.next` and
|
|
19
|
+
`CreateApiKeyBody.tiers`. All are optional and additive.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **The vendored contract is re-synced** from the released one (`docs.sendly.now/openapi.json`),
|
|
24
|
+
which had grown from 106 to 198 paths since the last sync. The additions are account, dashboard
|
|
25
|
+
and member-management routes plus key-callable operations this SDK has no method for yet; the
|
|
26
|
+
contract suite lists them in `NOT_SDK_CALLABLE` / `NOT_YET_IMPLEMENTED` rather than shipping
|
|
27
|
+
them unreviewed. No existing method changed.
|
|
28
|
+
|
|
8
29
|
## [1.2.0] - 2026-11-03
|
|
9
30
|
|
|
10
31
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sendly-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Official Python SDK for Sendly (sendly.now), the email API and platform for developers by Devino Solutions: transactional email, contacts, templates and webhooks.
|
|
5
5
|
Project-URL: Homepage, https://sendly.now
|
|
6
6
|
Project-URL: Documentation, https://docs.sendly.now
|
|
@@ -311,6 +311,26 @@ for event in email["events"]:
|
|
|
311
311
|
somebody opened, read `openedAt` / `opens` on the rows — engagement is not a
|
|
312
312
|
status.
|
|
313
313
|
|
|
314
|
+
A bounced or complained message says why. Each key below is `str | None` and is
|
|
315
|
+
`None` until the event happens (or when the receiving server did not say):
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
email = sendly.emails.get("em_123")["data"]
|
|
319
|
+
if email["status"] == "BOUNCED":
|
|
320
|
+
# `bounceType` is "Permanent" or "Undetermined" here (a "Transient" bounce is
|
|
321
|
+
# retried and never sets BOUNCED); the rest are the receiving server's own words.
|
|
322
|
+
# Show them to a person, do not parse them.
|
|
323
|
+
print(email["bounceType"], email["bounceSubType"],
|
|
324
|
+
email["bounceStatusCode"], email["bounceDiagnosticCode"])
|
|
325
|
+
if email["complainedAt"] is not None:
|
|
326
|
+
print(email["complaintFeedbackType"]) # e.g. "abuse"
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Each entry of `email["events"]` carries the same four `bounce*` keys for the
|
|
330
|
+
transition that recorded them. The `email.bounced` webhook body adds
|
|
331
|
+
`bounceSubType`, `bounceStatusCode` and `bounceDiagnosticCode`, and
|
|
332
|
+
`email.complained` adds `complaintFeedbackType`.
|
|
333
|
+
|
|
314
334
|
### Contacts
|
|
315
335
|
|
|
316
336
|
```python
|
|
@@ -279,6 +279,26 @@ for event in email["events"]:
|
|
|
279
279
|
somebody opened, read `openedAt` / `opens` on the rows — engagement is not a
|
|
280
280
|
status.
|
|
281
281
|
|
|
282
|
+
A bounced or complained message says why. Each key below is `str | None` and is
|
|
283
|
+
`None` until the event happens (or when the receiving server did not say):
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
email = sendly.emails.get("em_123")["data"]
|
|
287
|
+
if email["status"] == "BOUNCED":
|
|
288
|
+
# `bounceType` is "Permanent" or "Undetermined" here (a "Transient" bounce is
|
|
289
|
+
# retried and never sets BOUNCED); the rest are the receiving server's own words.
|
|
290
|
+
# Show them to a person, do not parse them.
|
|
291
|
+
print(email["bounceType"], email["bounceSubType"],
|
|
292
|
+
email["bounceStatusCode"], email["bounceDiagnosticCode"])
|
|
293
|
+
if email["complainedAt"] is not None:
|
|
294
|
+
print(email["complaintFeedbackType"]) # e.g. "abuse"
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Each entry of `email["events"]` carries the same four `bounce*` keys for the
|
|
298
|
+
transition that recorded them. The `email.bounced` webhook body adds
|
|
299
|
+
`bounceSubType`, `bounceStatusCode` and `bounceDiagnosticCode`, and
|
|
300
|
+
`email.complained` adds `complaintFeedbackType`.
|
|
301
|
+
|
|
282
302
|
### Contacts
|
|
283
303
|
|
|
284
304
|
```python
|
|
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
|
8
8
|
# the PyPI trusted-publisher configuration). The import package is
|
|
9
9
|
# unchanged (`import sendly`) — see [tool.hatch.build.targets.wheel] below.
|
|
10
10
|
name = "sendly-python"
|
|
11
|
-
version = "1.
|
|
11
|
+
version = "1.3.0"
|
|
12
12
|
description = "Official Python SDK for Sendly (sendly.now), the email API and platform for developers by Devino Solutions: transactional email, contacts, templates and webhooks."
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
requires-python = ">=3.10"
|
|
@@ -64,7 +64,7 @@ if TYPE_CHECKING:
|
|
|
64
64
|
__all__ = ["DEFAULT_BASE_URL", "SDK_VERSION", "Sendly"]
|
|
65
65
|
|
|
66
66
|
#: Package version. Kept in sync with ``pyproject.toml``.
|
|
67
|
-
SDK_VERSION = "1.
|
|
67
|
+
SDK_VERSION = "1.3.0"
|
|
68
68
|
|
|
69
69
|
#: Default production API base. Override via ``base_url`` for staging/self-hosted.
|
|
70
70
|
DEFAULT_BASE_URL = "https://api.sendly.now"
|
|
@@ -39,12 +39,16 @@ Pagination = JSONDict
|
|
|
39
39
|
SendEmailData = JSONDict
|
|
40
40
|
SendEmailResponse = JSONDict
|
|
41
41
|
BatchSendResponse = JSONDict
|
|
42
|
+
#: An email row. Beyond the delivery fields it carries, ``str | None`` and ``None``
|
|
43
|
+
#: until the event happens, ``bounceType``, ``bounceSubType``, ``bounceStatusCode``,
|
|
44
|
+
#: ``bounceDiagnosticCode`` and ``complaintFeedbackType``.
|
|
42
45
|
EmailRecord = JSONDict
|
|
43
46
|
EmailListResponse = JSONDict
|
|
44
47
|
|
|
45
48
|
#: One transition in a message's delivery history -- the append-only record
|
|
46
49
|
#: behind ``status``. ``status`` says where the message is now; these say how it
|
|
47
|
-
#: got there.
|
|
50
|
+
#: got there. A bounce transition also carries ``bounceType``, ``bounceSubType``,
|
|
51
|
+
#: ``bounceStatusCode`` and ``bounceDiagnosticCode`` (each ``str | None``).
|
|
48
52
|
EmailEvent = JSONDict
|
|
49
53
|
#: An email together with its delivery history, oldest first.
|
|
50
54
|
EmailWithEvents = JSONDict
|