gork-sdk 1.0.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.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: gork-sdk
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for gork.email programmable email infrastructure for AI agents
5
+ Author: gork.email
6
+ License: MIT
7
+ Project-URL: Homepage, https://gork.email
8
+ Project-URL: Documentation, https://gork.email/docs
9
+ Project-URL: Repository, https://github.com/shyamcxy/gork-sdk
10
+ Keywords: email,agent,ai,mcp,inbox,mail
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Topic :: Communications :: Email
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+
18
+ # gork-sdk — Python SDK for gork.email
19
+
20
+ Programmable email infrastructure for AI agents. Provision inboxes, send and receive mail, manage threads, webhooks, domains, keys, and suppressions.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install gork-sdk
26
+ ```
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from gork import GorkClient
32
+
33
+ gork = GorkClient() # reads GORK_KEY / GORK_API_KEY
34
+
35
+ inbox = gork.create_inbox(username="sdr-alex", name="SDR Alex")
36
+ print(inbox["address"]) # sdr-alex@gork.email
37
+
38
+ gork.send_message(
39
+ inbox_id=inbox["id"],
40
+ to=["prospect@acme.com"],
41
+ subject="Quick intro",
42
+ text="Hi — wanted to share what we're building.",
43
+ idempotency_key="outreach-001", # safe retries
44
+ )
45
+ ```
46
+
47
+ ## Webhook verification
48
+
49
+ ```python
50
+ from gork import verify_signature
51
+
52
+ ok = verify_signature(raw_body, request.headers["X-Gork-Signature"], webhook_secret)
53
+ ```
54
+
55
+ ## Links
56
+
57
+ - Docs: https://gork.email/docs
58
+ - API reference: https://api.gork.email/openapi.json
59
+ - Changelog: https://gork.email/changelog
@@ -0,0 +1,42 @@
1
+ # gork-sdk — Python SDK for gork.email
2
+
3
+ Programmable email infrastructure for AI agents. Provision inboxes, send and receive mail, manage threads, webhooks, domains, keys, and suppressions.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install gork-sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```python
14
+ from gork import GorkClient
15
+
16
+ gork = GorkClient() # reads GORK_KEY / GORK_API_KEY
17
+
18
+ inbox = gork.create_inbox(username="sdr-alex", name="SDR Alex")
19
+ print(inbox["address"]) # sdr-alex@gork.email
20
+
21
+ gork.send_message(
22
+ inbox_id=inbox["id"],
23
+ to=["prospect@acme.com"],
24
+ subject="Quick intro",
25
+ text="Hi — wanted to share what we're building.",
26
+ idempotency_key="outreach-001", # safe retries
27
+ )
28
+ ```
29
+
30
+ ## Webhook verification
31
+
32
+ ```python
33
+ from gork import verify_signature
34
+
35
+ ok = verify_signature(raw_body, request.headers["X-Gork-Signature"], webhook_secret)
36
+ ```
37
+
38
+ ## Links
39
+
40
+ - Docs: https://gork.email/docs
41
+ - API reference: https://api.gork.email/openapi.json
42
+ - Changelog: https://gork.email/changelog
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gork-sdk"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for gork.email programmable email infrastructure for AI agents"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "gork.email" }]
13
+ keywords = ["email", "agent", "ai", "mcp", "inbox", "mail"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Topic :: Communications :: Email",
18
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
19
+ ]
20
+
21
+ [project.urls]
22
+ Homepage = "https://gork.email"
23
+ Documentation = "https://gork.email/docs"
24
+ Repository = "https://github.com/shyamcxy/gork-sdk"
25
+
26
+ [tool.setuptools.packages.find]
27
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ """gork.email Python SDK — programmable email infrastructure for AI agents."""
2
+
3
+ from .client import GorkClient
4
+ from .errors import GorkError
5
+ from .types import Inbox, Message, Thread, Webhook, ApiKey, Domain, Suppression
6
+
7
+ __all__ = [
8
+ "GorkClient",
9
+ "GorkError",
10
+ "Inbox",
11
+ "Message",
12
+ "Thread",
13
+ "Webhook",
14
+ "ApiKey",
15
+ "Domain",
16
+ "Suppression",
17
+ ]
18
+
19
+ __version__ = "1.0.0"
@@ -0,0 +1,180 @@
1
+ """GorkClient — zero-dependency (stdlib only) REST client for api.gork.email."""
2
+
3
+ import hashlib
4
+ import hmac
5
+ import json
6
+ import os
7
+ import urllib.parse
8
+ import urllib.request
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from .errors import GorkError
12
+
13
+ DEFAULT_BASE_URL = "https://api.gork.email"
14
+
15
+
16
+ def verify_signature(payload: str, signature_header: str, secret: str) -> bool:
17
+ """Verify an X-Gork-Signature webhook header (HMAC-SHA256, timestamp-tolerated)."""
18
+ try:
19
+ parts = dict(p.split("=", 1) for p in signature_header.split(",") if "=" in p)
20
+ timestamp, signature = parts.get("t", ""), parts.get("v1", "")
21
+ if not timestamp or not signature:
22
+ return False
23
+ expected = hmac.new(
24
+ secret.encode(), f"{timestamp}.{payload}".encode(), hashlib.sha256
25
+ ).hexdigest()
26
+ return hmac.compare_digest(signature, expected)
27
+ except Exception:
28
+ return False
29
+
30
+
31
+ class GorkClient:
32
+ def __init__(self, api_key: str = "", base_url: str = DEFAULT_BASE_URL):
33
+ self.api_key = api_key or os.environ.get("GORK_KEY") or os.environ.get("GORK_API_KEY") or ""
34
+ self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
35
+ if not self.api_key:
36
+ import warnings
37
+
38
+ warnings.warn(
39
+ "[gork] initialized without an api_key. Set GORK_KEY or pass api_key explicitly."
40
+ )
41
+
42
+ def _request(
43
+ self,
44
+ method: str,
45
+ path: str,
46
+ body: Optional[Dict[str, Any]] = None,
47
+ query: Optional[Dict[str, Any]] = None,
48
+ headers: Optional[Dict[str, str]] = None,
49
+ ) -> Any:
50
+ url = self.base_url + path
51
+ if query:
52
+ url += "?" + urllib.parse.urlencode({k: v for k, v in query.items() if v is not None})
53
+ data = json.dumps(body).encode() if body is not None else None
54
+ req = urllib.request.Request(url, data=data, method=method)
55
+ req.add_header("Authorization", f"Bearer {self.api_key}")
56
+ req.add_header("Content-Type", "application/json")
57
+ req.add_header("User-Agent", "gork-sdk-python/1.0.0")
58
+ for k, v in (headers or {}).items():
59
+ req.add_header(k, v)
60
+ try:
61
+ with urllib.request.urlopen(req, timeout=30) as res:
62
+ payload = json.loads(res.read().decode() or "{}")
63
+ except urllib.error.HTTPError as e:
64
+ try:
65
+ payload = json.loads(e.read().decode() or "{}")
66
+ except Exception:
67
+ payload = {}
68
+ err = (payload.get("error") or {}) if isinstance(payload, dict) else {}
69
+ raise GorkError(
70
+ err.get("message") or f"API request failed with status {e.code}",
71
+ err.get("code") or "api_error",
72
+ e.code,
73
+ err.get("details"),
74
+ )
75
+ data_key = payload.get("data", payload) if isinstance(payload, dict) else payload
76
+ return data_key
77
+
78
+ # ---- Inboxes ----
79
+ def create_inbox(self, username: str = "", name: str = "") -> Dict[str, Any]:
80
+ return self._request("POST", "/v1/inboxes", {"username": username, "name": name})
81
+
82
+ def list_inboxes(self) -> List[Dict[str, Any]]:
83
+ return self._request("GET", "/v1/inboxes")
84
+
85
+ def get_inbox(self, inbox_id: str) -> Dict[str, Any]:
86
+ return self._request("GET", f"/v1/inboxes/{urllib.parse.quote(inbox_id)}")
87
+
88
+ def delete_inbox(self, inbox_id: str) -> Dict[str, Any]:
89
+ return self._request("DELETE", f"/v1/inboxes/{urllib.parse.quote(inbox_id)}")
90
+
91
+ # ---- Messages ----
92
+ def send_message(
93
+ self,
94
+ inbox_id: str,
95
+ to: List[str],
96
+ subject: str = "(no subject)",
97
+ text: str = "",
98
+ html: str = "",
99
+ in_reply_to: str = "",
100
+ idempotency_key: str = "",
101
+ ) -> Dict[str, Any]:
102
+ body: Dict[str, Any] = {"inboxId": inbox_id, "to": to, "subject": subject}
103
+ if text:
104
+ body["text"] = text
105
+ if html:
106
+ body["html"] = html
107
+ if in_reply_to:
108
+ body["inReplyTo"] = in_reply_to
109
+ headers = {"Idempotency-Key": idempotency_key} if idempotency_key else None
110
+ return self._request("POST", "/v1/messages/send", body, headers=headers)
111
+
112
+ def list_messages(
113
+ self, inbox_id: str = "", thread_id: str = "", limit: int = 50
114
+ ) -> List[Dict[str, Any]]:
115
+ return self._request(
116
+ "GET", "/v1/messages",
117
+ query={"inboxId": inbox_id or None, "threadId": thread_id or None, "limit": limit},
118
+ )
119
+
120
+ def get_message(self, message_id: str) -> Dict[str, Any]:
121
+ return self._request("GET", f"/v1/messages/{urllib.parse.quote(message_id)}")
122
+
123
+ # ---- Threads ----
124
+ def list_threads(self) -> List[Dict[str, Any]]:
125
+ return self._request("GET", "/v1/threads")
126
+
127
+ def get_thread(self, thread_id: str) -> Dict[str, Any]:
128
+ return self._request("GET", f"/v1/threads/{urllib.parse.quote(thread_id)}")
129
+
130
+ # ---- Webhooks ----
131
+ def create_webhook(self, url: str, events: Optional[List[str]] = None) -> Dict[str, Any]:
132
+ return self._request(
133
+ "POST", "/v1/webhooks",
134
+ {"url": url, "subscribedEvents": events or ["email.received", "email.sent", "email.bounced"]},
135
+ )
136
+
137
+ def list_webhooks(self) -> List[Dict[str, Any]]:
138
+ return self._request("GET", "/v1/webhooks")
139
+
140
+ def rotate_webhook_secret(self, webhook_id: str) -> Dict[str, Any]:
141
+ return self._request("POST", f"/v1/webhooks/{urllib.parse.quote(webhook_id)}/rotate-secret")
142
+
143
+ def delete_webhook(self, webhook_id: str) -> Dict[str, Any]:
144
+ return self._request("DELETE", f"/v1/webhooks/{urllib.parse.quote(webhook_id)}")
145
+
146
+ def list_deliveries(self, limit: int = 50) -> List[Dict[str, Any]]:
147
+ return self._request("GET", "/v1/webhooks/deliveries", query={"limit": limit})
148
+
149
+ # ---- API keys ----
150
+ def create_api_key(self, name: str, scopes: Optional[List[str]] = None) -> Dict[str, Any]:
151
+ return self._request("POST", "/v1/keys", {"name": name, "scopes": scopes or ["*"]})
152
+
153
+ def list_api_keys(self) -> List[Dict[str, Any]]:
154
+ return self._request("GET", "/v1/keys")
155
+
156
+ def revoke_api_key(self, key_id: str) -> Dict[str, Any]:
157
+ return self._request("DELETE", f"/v1/keys/{urllib.parse.quote(key_id)}")
158
+
159
+ # ---- Domains ----
160
+ def create_domain(self, domain: str) -> Dict[str, Any]:
161
+ return self._request("POST", "/v1/domains", {"domain": domain})
162
+
163
+ def list_domains(self) -> List[Dict[str, Any]]:
164
+ return self._request("GET", "/v1/domains")
165
+
166
+ def verify_domain(self, domain_id: str) -> Dict[str, Any]:
167
+ return self._request("POST", f"/v1/domains/{urllib.parse.quote(domain_id)}/verify")
168
+
169
+ def delete_domain(self, domain_id: str) -> Dict[str, Any]:
170
+ return self._request("DELETE", f"/v1/domains/{urllib.parse.quote(domain_id)}")
171
+
172
+ # ---- Suppressions ----
173
+ def list_suppressions(self) -> List[Dict[str, Any]]:
174
+ return self._request("GET", "/v1/suppressions")
175
+
176
+ def suppress(self, email: str, reason: str = "manual") -> Dict[str, Any]:
177
+ return self._request("POST", "/v1/suppressions", {"email": email, "reason": reason})
178
+
179
+ def unsuppress(self, suppression_id: str) -> Dict[str, Any]:
180
+ return self._request("DELETE", f"/v1/suppressions/{urllib.parse.quote(suppression_id)}")
@@ -0,0 +1,9 @@
1
+ """Error type carrying the API's stable error code."""
2
+
3
+
4
+ class GorkError(Exception):
5
+ def __init__(self, message: str, code: str = "api_error", status: int = 0, details=None):
6
+ super().__init__(message)
7
+ self.code = code
8
+ self.status = status
9
+ self.details = details
@@ -0,0 +1,59 @@
1
+ """TypedDict shapes mirroring the gork.email API envelopes."""
2
+
3
+ from typing import List, Optional, TypedDict
4
+
5
+
6
+ class Inbox(TypedDict, total=False):
7
+ id: str
8
+ address: str
9
+ name: Optional[str]
10
+ isActive: bool
11
+ createdAt: str
12
+
13
+
14
+ class Message(TypedDict, total=False):
15
+ id: str
16
+ threadId: str
17
+ inboxId: str
18
+ direction: str
19
+ fromAddress: str
20
+ subject: str
21
+ textBody: Optional[str]
22
+ status: str
23
+ createdAt: str
24
+
25
+
26
+ class Thread(TypedDict, total=False):
27
+ id: str
28
+ subject: str
29
+ messageCount: int
30
+ lastMessageAt: str
31
+
32
+
33
+ class Webhook(TypedDict, total=False):
34
+ id: str
35
+ url: str
36
+ subscribedEvents: List[str]
37
+ isActive: bool
38
+ secret: Optional[str]
39
+
40
+
41
+ class ApiKey(TypedDict, total=False):
42
+ id: str
43
+ name: str
44
+ keyPrefix: str
45
+ apiKey: Optional[str]
46
+ scopes: List[str]
47
+ createdAt: str
48
+
49
+
50
+ class Domain(TypedDict, total=False):
51
+ id: str
52
+ domainName: str
53
+ status: str
54
+
55
+
56
+ class Suppression(TypedDict, total=False):
57
+ id: str
58
+ email: str
59
+ reason: str
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: gork-sdk
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for gork.email programmable email infrastructure for AI agents
5
+ Author: gork.email
6
+ License: MIT
7
+ Project-URL: Homepage, https://gork.email
8
+ Project-URL: Documentation, https://gork.email/docs
9
+ Project-URL: Repository, https://github.com/shyamcxy/gork-sdk
10
+ Keywords: email,agent,ai,mcp,inbox,mail
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Topic :: Communications :: Email
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+
18
+ # gork-sdk — Python SDK for gork.email
19
+
20
+ Programmable email infrastructure for AI agents. Provision inboxes, send and receive mail, manage threads, webhooks, domains, keys, and suppressions.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install gork-sdk
26
+ ```
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from gork import GorkClient
32
+
33
+ gork = GorkClient() # reads GORK_KEY / GORK_API_KEY
34
+
35
+ inbox = gork.create_inbox(username="sdr-alex", name="SDR Alex")
36
+ print(inbox["address"]) # sdr-alex@gork.email
37
+
38
+ gork.send_message(
39
+ inbox_id=inbox["id"],
40
+ to=["prospect@acme.com"],
41
+ subject="Quick intro",
42
+ text="Hi — wanted to share what we're building.",
43
+ idempotency_key="outreach-001", # safe retries
44
+ )
45
+ ```
46
+
47
+ ## Webhook verification
48
+
49
+ ```python
50
+ from gork import verify_signature
51
+
52
+ ok = verify_signature(raw_body, request.headers["X-Gork-Signature"], webhook_secret)
53
+ ```
54
+
55
+ ## Links
56
+
57
+ - Docs: https://gork.email/docs
58
+ - API reference: https://api.gork.email/openapi.json
59
+ - Changelog: https://gork.email/changelog
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/gork/__init__.py
4
+ src/gork/client.py
5
+ src/gork/errors.py
6
+ src/gork/types.py
7
+ src/gork_sdk.egg-info/PKG-INFO
8
+ src/gork_sdk.egg-info/SOURCES.txt
9
+ src/gork_sdk.egg-info/dependency_links.txt
10
+ src/gork_sdk.egg-info/top_level.txt