poststack 0.4.0__tar.gz → 0.9.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.
- {poststack-0.4.0 → poststack-0.9.0}/PKG-INFO +31 -17
- {poststack-0.4.0 → poststack-0.9.0}/README.md +28 -14
- {poststack-0.4.0 → poststack-0.9.0}/pyproject.toml +6 -2
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/__init__.py +22 -7
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/_client.py +500 -333
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/_errors.py +8 -1
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/__init__.py +9 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/api_keys.py +26 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/broadcasts.py +134 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/contact_properties.py +16 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/contacts.py +62 -7
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/domains.py +119 -2
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/emails.py +46 -0
- poststack-0.9.0/src/poststack/resources/inbound_emails.py +147 -0
- poststack-0.9.0/src/poststack/resources/mailboxes.py +345 -0
- poststack-0.9.0/src/poststack/resources/notification_channels.py +179 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/segments.py +72 -0
- poststack-0.9.0/src/poststack/resources/subscription_topics.py +184 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/templates.py +38 -0
- poststack-0.9.0/src/poststack/resources/webhooks.py +303 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/workflows.py +84 -51
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/types.py +206 -21
- poststack-0.9.0/tests/__init__.py +0 -0
- poststack-0.9.0/tests/test_api_parity.py +491 -0
- {poststack-0.4.0 → poststack-0.9.0}/tests/test_client.py +119 -13
- poststack-0.9.0/tests/test_webhooks_verify.py +60 -0
- poststack-0.4.0/src/poststack/resources/mailboxes.py +0 -157
- poststack-0.4.0/src/poststack/resources/subscription_topics.py +0 -119
- poststack-0.4.0/src/poststack/resources/webhooks.py +0 -139
- {poststack-0.4.0 → poststack-0.9.0}/.gitignore +0 -0
- {poststack-0.4.0 → poststack-0.9.0}/LICENSE +0 -0
- /poststack-0.4.0/tests/__init__.py → /poststack-0.9.0/src/poststack/py.typed +0 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/email_validations.py +0 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/signup_forms.py +0 -0
- {poststack-0.4.0 → poststack-0.9.0}/src/poststack/resources/suppressions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: poststack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Official Python SDK for the PostStack Email API
|
|
5
5
|
Project-URL: Homepage, https://poststack.dev
|
|
6
6
|
Project-URL: Documentation, https://poststack.dev/docs
|
|
@@ -22,7 +22,7 @@ Classifier: Topic :: Communications :: Email
|
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: httpx>=0.25.0
|
|
25
|
-
Requires-Dist: pydantic>=2.
|
|
25
|
+
Requires-Dist: pydantic>=2.4.0
|
|
26
26
|
Provides-Extra: dev
|
|
27
27
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
28
28
|
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
@@ -105,16 +105,28 @@ client = PostStack(api_key="sk_live_...")
|
|
|
105
105
|
try:
|
|
106
106
|
client.emails.send({"from": "x@y.com", "to": ["z@w.com"], "subject": "hi"})
|
|
107
107
|
except PostStackError as e:
|
|
108
|
-
print(e.status_code, e.error, e.request_id)
|
|
108
|
+
print(e.status_code, e.error, e.code, e.request_id)
|
|
109
|
+
# e.headers holds the response headers; e.retry_after the Retry-After
|
|
110
|
+
# delay in seconds, when the API sent one.
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
## Retries
|
|
114
|
+
|
|
115
|
+
Network errors, timeouts, 408, 429 and 5xx responses are retried up to
|
|
116
|
+
`max_retries` times (default 3) with full-jitter exponential backoff. A 429
|
|
117
|
+
that carries `Retry-After` waits exactly that long (up to 60 seconds; a longer
|
|
118
|
+
wait is raised instead). A 429 that is a quota rather than throttling — the
|
|
119
|
+
monthly plan limit or the daily send cap, which carry an error code and no
|
|
120
|
+
`Retry-After` — is raised immediately, since retrying cannot lift it.
|
|
121
|
+
|
|
111
122
|
## Configuration
|
|
112
123
|
|
|
113
124
|
```python
|
|
114
125
|
client = PostStack(
|
|
115
126
|
api_key="sk_live_...",
|
|
116
127
|
base_url="https://api.poststack.dev", # default
|
|
117
|
-
timeout=30.0, # default (seconds)
|
|
128
|
+
timeout=30.0, # default (seconds), per attempt
|
|
129
|
+
max_retries=3, # default; 0 disables retrying
|
|
118
130
|
)
|
|
119
131
|
```
|
|
120
132
|
|
|
@@ -126,19 +138,21 @@ client.emails.send({...}, timeout=60.0)
|
|
|
126
138
|
|
|
127
139
|
## Resources
|
|
128
140
|
|
|
129
|
-
- `client.emails` — send, get, list, cancel, reschedule, batch, events, insights
|
|
130
|
-
- `client.domains` — create, list, get, verify, update, delete, DMARC
|
|
131
|
-
- `client.contacts` — CRUD, import,
|
|
132
|
-
- `client.contact_properties` — custom properties
|
|
133
|
-
- `client.segments` — create, list, get, update, delete, contacts, preview
|
|
134
|
-
- `client.templates` — CRUD, publish, duplicate, presets
|
|
135
|
-
- `client.webhooks` — CRUD, test, deliveries, replay
|
|
136
|
-
- `client.broadcasts` — CRUD, send, test, variants
|
|
141
|
+
- `client.emails` — send, get, list, cancel, reschedule, batch, events, insights, preview, spam_preview
|
|
142
|
+
- `client.domains` — create, list, get, verify, update, delete, DMARC, DKIM rotation, inbox placement
|
|
143
|
+
- `client.contacts` — CRUD, import, export_csv (text; optional `segment_id`), unsubscribe
|
|
144
|
+
- `client.contact_properties` — custom properties, option_usage
|
|
145
|
+
- `client.segments` — create, list, get, update, delete, contacts, preview, members, growth, broadcasts
|
|
146
|
+
- `client.templates` — CRUD, publish, duplicate, render, presets
|
|
147
|
+
- `client.webhooks` — CRUD, test, deliveries, replay, batch_replay, rotate_secret
|
|
148
|
+
- `client.broadcasts` — CRUD, send, test, variants, resend, performance, non_openers, non_clickers, end_ab_test
|
|
137
149
|
- `client.suppressions` — list, add, remove
|
|
138
|
-
- `client.api_keys` — CRUD
|
|
139
|
-
- `client.mailboxes` — CRUD, aliases, password
|
|
140
|
-
- `client.
|
|
141
|
-
- `client.
|
|
150
|
+
- `client.api_keys` — CRUD, rotate
|
|
151
|
+
- `client.mailboxes` — CRUD, aliases, password, filters, signature, shares, unread_summary
|
|
152
|
+
- `client.inbound_emails` — list, get, attachments, download, draft_reply, reply, forward
|
|
153
|
+
- `client.subscription_topics` — topics (get, update, list_subscribers) + contact subscriptions
|
|
154
|
+
- `client.workflows` — CRUD, graph (get_graph/put_graph/validate_graph), activate, pause, trigger, post_event
|
|
155
|
+
- `client.notification_channels` — Slack/Discord/Telegram alert channels: CRUD, test, deliveries, replay
|
|
142
156
|
- `client.signup_forms` — CRUD, submit
|
|
143
157
|
- `client.email_validations` — validate, validate_batch
|
|
144
158
|
|
|
@@ -74,16 +74,28 @@ client = PostStack(api_key="sk_live_...")
|
|
|
74
74
|
try:
|
|
75
75
|
client.emails.send({"from": "x@y.com", "to": ["z@w.com"], "subject": "hi"})
|
|
76
76
|
except PostStackError as e:
|
|
77
|
-
print(e.status_code, e.error, e.request_id)
|
|
77
|
+
print(e.status_code, e.error, e.code, e.request_id)
|
|
78
|
+
# e.headers holds the response headers; e.retry_after the Retry-After
|
|
79
|
+
# delay in seconds, when the API sent one.
|
|
78
80
|
```
|
|
79
81
|
|
|
82
|
+
## Retries
|
|
83
|
+
|
|
84
|
+
Network errors, timeouts, 408, 429 and 5xx responses are retried up to
|
|
85
|
+
`max_retries` times (default 3) with full-jitter exponential backoff. A 429
|
|
86
|
+
that carries `Retry-After` waits exactly that long (up to 60 seconds; a longer
|
|
87
|
+
wait is raised instead). A 429 that is a quota rather than throttling — the
|
|
88
|
+
monthly plan limit or the daily send cap, which carry an error code and no
|
|
89
|
+
`Retry-After` — is raised immediately, since retrying cannot lift it.
|
|
90
|
+
|
|
80
91
|
## Configuration
|
|
81
92
|
|
|
82
93
|
```python
|
|
83
94
|
client = PostStack(
|
|
84
95
|
api_key="sk_live_...",
|
|
85
96
|
base_url="https://api.poststack.dev", # default
|
|
86
|
-
timeout=30.0, # default (seconds)
|
|
97
|
+
timeout=30.0, # default (seconds), per attempt
|
|
98
|
+
max_retries=3, # default; 0 disables retrying
|
|
87
99
|
)
|
|
88
100
|
```
|
|
89
101
|
|
|
@@ -95,19 +107,21 @@ client.emails.send({...}, timeout=60.0)
|
|
|
95
107
|
|
|
96
108
|
## Resources
|
|
97
109
|
|
|
98
|
-
- `client.emails` — send, get, list, cancel, reschedule, batch, events, insights
|
|
99
|
-
- `client.domains` — create, list, get, verify, update, delete, DMARC
|
|
100
|
-
- `client.contacts` — CRUD, import,
|
|
101
|
-
- `client.contact_properties` — custom properties
|
|
102
|
-
- `client.segments` — create, list, get, update, delete, contacts, preview
|
|
103
|
-
- `client.templates` — CRUD, publish, duplicate, presets
|
|
104
|
-
- `client.webhooks` — CRUD, test, deliveries, replay
|
|
105
|
-
- `client.broadcasts` — CRUD, send, test, variants
|
|
110
|
+
- `client.emails` — send, get, list, cancel, reschedule, batch, events, insights, preview, spam_preview
|
|
111
|
+
- `client.domains` — create, list, get, verify, update, delete, DMARC, DKIM rotation, inbox placement
|
|
112
|
+
- `client.contacts` — CRUD, import, export_csv (text; optional `segment_id`), unsubscribe
|
|
113
|
+
- `client.contact_properties` — custom properties, option_usage
|
|
114
|
+
- `client.segments` — create, list, get, update, delete, contacts, preview, members, growth, broadcasts
|
|
115
|
+
- `client.templates` — CRUD, publish, duplicate, render, presets
|
|
116
|
+
- `client.webhooks` — CRUD, test, deliveries, replay, batch_replay, rotate_secret
|
|
117
|
+
- `client.broadcasts` — CRUD, send, test, variants, resend, performance, non_openers, non_clickers, end_ab_test
|
|
106
118
|
- `client.suppressions` — list, add, remove
|
|
107
|
-
- `client.api_keys` — CRUD
|
|
108
|
-
- `client.mailboxes` — CRUD, aliases, password
|
|
109
|
-
- `client.
|
|
110
|
-
- `client.
|
|
119
|
+
- `client.api_keys` — CRUD, rotate
|
|
120
|
+
- `client.mailboxes` — CRUD, aliases, password, filters, signature, shares, unread_summary
|
|
121
|
+
- `client.inbound_emails` — list, get, attachments, download, draft_reply, reply, forward
|
|
122
|
+
- `client.subscription_topics` — topics (get, update, list_subscribers) + contact subscriptions
|
|
123
|
+
- `client.workflows` — CRUD, graph (get_graph/put_graph/validate_graph), activate, pause, trigger, post_event
|
|
124
|
+
- `client.notification_channels` — Slack/Discord/Telegram alert channels: CRUD, test, deliveries, replay
|
|
111
125
|
- `client.signup_forms` — CRUD, submit
|
|
112
126
|
- `client.email_validations` — validate, validate_batch
|
|
113
127
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "poststack"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.9.0"
|
|
8
8
|
description = "Official Python SDK for the PostStack Email API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -25,7 +25,8 @@ classifiers = [
|
|
|
25
25
|
]
|
|
26
26
|
dependencies = [
|
|
27
27
|
"httpx>=0.25.0",
|
|
28
|
-
|
|
28
|
+
# 2.4.0 floor closes GHSA-mr82-8j83-vxmv (regex DoS in 2.0–2.3.x).
|
|
29
|
+
"pydantic>=2.4.0",
|
|
29
30
|
]
|
|
30
31
|
|
|
31
32
|
[project.optional-dependencies]
|
|
@@ -43,6 +44,9 @@ Issues = "https://github.com/getpoststack/python-sdk/issues"
|
|
|
43
44
|
|
|
44
45
|
[tool.hatch.build.targets.wheel]
|
|
45
46
|
packages = ["src/poststack"]
|
|
47
|
+
# PEP 561: ship the `py.typed` marker so downstream type checkers (mypy,
|
|
48
|
+
# pyright) honor our annotations.
|
|
49
|
+
include = ["src/poststack/py.typed"]
|
|
46
50
|
|
|
47
51
|
[tool.hatch.build.targets.sdist]
|
|
48
52
|
include = [
|
|
@@ -10,10 +10,9 @@ Public API::
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
-
from typing import Optional
|
|
14
|
-
|
|
15
13
|
from ._client import (
|
|
16
14
|
DEFAULT_BASE_URL,
|
|
15
|
+
DEFAULT_MAX_RETRIES,
|
|
17
16
|
AsyncPostStackClient,
|
|
18
17
|
PostStackClient,
|
|
19
18
|
)
|
|
@@ -27,7 +26,9 @@ from .resources import (
|
|
|
27
26
|
AsyncDomainsResource,
|
|
28
27
|
AsyncEmailsResource,
|
|
29
28
|
AsyncEmailValidationsResource,
|
|
29
|
+
AsyncInboundEmailsResource,
|
|
30
30
|
AsyncMailboxesResource,
|
|
31
|
+
AsyncNotificationChannelsResource,
|
|
31
32
|
AsyncSegmentsResource,
|
|
32
33
|
AsyncSignupFormsResource,
|
|
33
34
|
AsyncSubscriptionTopicsResource,
|
|
@@ -41,7 +42,9 @@ from .resources import (
|
|
|
41
42
|
DomainsResource,
|
|
42
43
|
EmailsResource,
|
|
43
44
|
EmailValidationsResource,
|
|
45
|
+
InboundEmailsResource,
|
|
44
46
|
MailboxesResource,
|
|
47
|
+
NotificationChannelsResource,
|
|
45
48
|
SegmentsResource,
|
|
46
49
|
SignupFormsResource,
|
|
47
50
|
SubscriptionTopicsResource,
|
|
@@ -51,7 +54,7 @@ from .resources import (
|
|
|
51
54
|
WorkflowsResource,
|
|
52
55
|
)
|
|
53
56
|
|
|
54
|
-
__version__ = "0.
|
|
57
|
+
__version__ = "0.9.0"
|
|
55
58
|
|
|
56
59
|
__all__ = [
|
|
57
60
|
"PostStack",
|
|
@@ -81,9 +84,13 @@ class PostStack:
|
|
|
81
84
|
api_key: str,
|
|
82
85
|
base_url: str = DEFAULT_BASE_URL,
|
|
83
86
|
timeout: float = 30.0,
|
|
87
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
84
88
|
) -> None:
|
|
85
89
|
self._client = PostStackClient(
|
|
86
|
-
api_key=api_key,
|
|
90
|
+
api_key=api_key,
|
|
91
|
+
base_url=base_url,
|
|
92
|
+
timeout=timeout,
|
|
93
|
+
max_retries=max_retries,
|
|
87
94
|
)
|
|
88
95
|
self.emails = EmailsResource(self._client)
|
|
89
96
|
self.domains = DomainsResource(self._client)
|
|
@@ -96,10 +103,12 @@ class PostStack:
|
|
|
96
103
|
self.suppressions = SuppressionsResource(self._client)
|
|
97
104
|
self.api_keys = ApiKeysResource(self._client)
|
|
98
105
|
self.mailboxes = MailboxesResource(self._client)
|
|
106
|
+
self.inbound_emails = InboundEmailsResource(self._client)
|
|
99
107
|
self.subscription_topics = SubscriptionTopicsResource(self._client)
|
|
100
108
|
self.workflows = WorkflowsResource(self._client)
|
|
101
109
|
self.signup_forms = SignupFormsResource(self._client)
|
|
102
110
|
self.email_validations = EmailValidationsResource(self._client)
|
|
111
|
+
self.notification_channels = NotificationChannelsResource(self._client)
|
|
103
112
|
|
|
104
113
|
def close(self) -> None:
|
|
105
114
|
self._client.close()
|
|
@@ -125,9 +134,13 @@ class AsyncPostStack:
|
|
|
125
134
|
api_key: str,
|
|
126
135
|
base_url: str = DEFAULT_BASE_URL,
|
|
127
136
|
timeout: float = 30.0,
|
|
137
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
128
138
|
) -> None:
|
|
129
139
|
self._client = AsyncPostStackClient(
|
|
130
|
-
api_key=api_key,
|
|
140
|
+
api_key=api_key,
|
|
141
|
+
base_url=base_url,
|
|
142
|
+
timeout=timeout,
|
|
143
|
+
max_retries=max_retries,
|
|
131
144
|
)
|
|
132
145
|
self.emails = AsyncEmailsResource(self._client)
|
|
133
146
|
self.domains = AsyncDomainsResource(self._client)
|
|
@@ -140,10 +153,14 @@ class AsyncPostStack:
|
|
|
140
153
|
self.suppressions = AsyncSuppressionsResource(self._client)
|
|
141
154
|
self.api_keys = AsyncApiKeysResource(self._client)
|
|
142
155
|
self.mailboxes = AsyncMailboxesResource(self._client)
|
|
156
|
+
self.inbound_emails = AsyncInboundEmailsResource(self._client)
|
|
143
157
|
self.subscription_topics = AsyncSubscriptionTopicsResource(self._client)
|
|
144
158
|
self.workflows = AsyncWorkflowsResource(self._client)
|
|
145
159
|
self.signup_forms = AsyncSignupFormsResource(self._client)
|
|
146
160
|
self.email_validations = AsyncEmailValidationsResource(self._client)
|
|
161
|
+
self.notification_channels = AsyncNotificationChannelsResource(
|
|
162
|
+
self._client
|
|
163
|
+
)
|
|
147
164
|
|
|
148
165
|
async def aclose(self) -> None:
|
|
149
166
|
await self._client.aclose()
|
|
@@ -155,5 +172,3 @@ class AsyncPostStack:
|
|
|
155
172
|
await self.aclose()
|
|
156
173
|
|
|
157
174
|
|
|
158
|
-
# Re-export for advanced callers.
|
|
159
|
-
_: Optional[type] = None # noqa: E305 - keeps ruff/mypy happy with Optional import
|