mailglyph 2.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.
Files changed (36) hide show
  1. mailglyph-2.0.0/.github/workflows/ci.yml +30 -0
  2. mailglyph-2.0.0/.github/workflows/publish.yml +25 -0
  3. mailglyph-2.0.0/.github/workflows/release-please.yml +22 -0
  4. mailglyph-2.0.0/.gitignore +19 -0
  5. mailglyph-2.0.0/.release-please-manifest.json +3 -0
  6. mailglyph-2.0.0/AGENTS.md +34 -0
  7. mailglyph-2.0.0/CHANGELOG.md +45 -0
  8. mailglyph-2.0.0/LICENSE +21 -0
  9. mailglyph-2.0.0/PKG-INFO +218 -0
  10. mailglyph-2.0.0/README.md +184 -0
  11. mailglyph-2.0.0/docs/openapi.json +3341 -0
  12. mailglyph-2.0.0/pyproject.toml +70 -0
  13. mailglyph-2.0.0/release-please-config.json +11 -0
  14. mailglyph-2.0.0/src/mailglyph/__init__.py +47 -0
  15. mailglyph-2.0.0/src/mailglyph/_version.py +1 -0
  16. mailglyph-2.0.0/src/mailglyph/client.py +77 -0
  17. mailglyph-2.0.0/src/mailglyph/exceptions.py +46 -0
  18. mailglyph-2.0.0/src/mailglyph/http_client.py +227 -0
  19. mailglyph-2.0.0/src/mailglyph/models.py +163 -0
  20. mailglyph-2.0.0/src/mailglyph/py.typed +0 -0
  21. mailglyph-2.0.0/src/mailglyph/resources/__init__.py +18 -0
  22. mailglyph-2.0.0/src/mailglyph/resources/_utils.py +13 -0
  23. mailglyph-2.0.0/src/mailglyph/resources/campaigns.py +251 -0
  24. mailglyph-2.0.0/src/mailglyph/resources/contacts.py +129 -0
  25. mailglyph-2.0.0/src/mailglyph/resources/emails.py +113 -0
  26. mailglyph-2.0.0/src/mailglyph/resources/events.py +73 -0
  27. mailglyph-2.0.0/src/mailglyph/resources/segments.py +222 -0
  28. mailglyph-2.0.0/tests/conftest.py +9 -0
  29. mailglyph-2.0.0/tests/integration/test_api.py +260 -0
  30. mailglyph-2.0.0/tests/unit/test_campaigns.py +298 -0
  31. mailglyph-2.0.0/tests/unit/test_contacts.py +197 -0
  32. mailglyph-2.0.0/tests/unit/test_emails.py +307 -0
  33. mailglyph-2.0.0/tests/unit/test_errors.py +26 -0
  34. mailglyph-2.0.0/tests/unit/test_events.py +101 -0
  35. mailglyph-2.0.0/tests/unit/test_http_client.py +160 -0
  36. mailglyph-2.0.0/tests/unit/test_segments.py +234 -0
@@ -0,0 +1,30 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ branches: [main]
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install dependencies
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install -e .[dev]
23
+ - name: Ruff
24
+ run: ruff check .
25
+ - name: Mypy
26
+ run: mypy src/
27
+ - name: Pytest
28
+ run: pytest
29
+ - name: Build
30
+ run: python -m build
@@ -0,0 +1,25 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: read
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Upgrade pip
19
+ run: python -m pip install --upgrade pip
20
+ - name: Install build
21
+ run: pip install "build>=1.2"
22
+ - name: Build package
23
+ run: python -m build
24
+ - name: Publish to PyPI
25
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,22 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: write
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ release-please:
13
+ runs-on: ubuntu-latest
14
+ outputs:
15
+ release_created: ${{ steps.release.outputs.release_created }}
16
+ tag_name: ${{ steps.release.outputs.tag_name }}
17
+ steps:
18
+ - uses: googleapis/release-please-action@v4
19
+ id: release
20
+ with:
21
+ release-type: python
22
+ token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
@@ -0,0 +1,19 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.so
4
+ .Python
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .coverage
9
+ htmlcov/
10
+ .dist/
11
+ build/
12
+ dist/
13
+ *.egg-info/
14
+ .venv/
15
+ venv/
16
+ .env
17
+ .env.test
18
+ .DS_Store
19
+ docs/*.md
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "2.0.0"
3
+ }
@@ -0,0 +1,34 @@
1
+ # AGENTS.md
2
+
3
+ ## Project
4
+ This is the official MailGlyph Python SDK. See `./docs/` for the full specification.
5
+
6
+ ## Context Files (read these FIRST)
7
+ 1. [sdk-plan.md](./docs/sdk-plan.md) — Shared API spec, all 22 endpoints, auth rules, error hierarchy, testing strategy, release-please setup
8
+ 2. [sdk-plan-python.md](./docs/sdk-plan-python.md) — Python-specific implementation plan (structure, Pydantic models, workflows)
9
+ 3. [openapi.json](./docs/openapi.json) — OpenAPI 3.0.3 specification (source of truth for schemas)
10
+
11
+ ## Build Order
12
+ 1. Scaffold: `pyproject.toml` (name: `mailglyph`), `src/mailglyph/__init__.py`, `.gitignore`
13
+ 2. Exceptions (`src/mailglyph/exceptions.py`) — `MailGlyphError`, `AuthenticationError`, `ValidationError`, `NotFoundError`, `RateLimitError`, `ApiError`
14
+ 3. Models (`src/mailglyph/models.py`) — Pydantic BaseModel DTOs: `Contact`, `Segment`, `Campaign`, `SendEmailResult`, `VerifyEmailResult`, `TrackEventResult`
15
+ 4. HttpClient (`src/mailglyph/http_client.py`) — httpx transport, Bearer auth, JSON parsing, error mapping, retry with exponential backoff for 429/5xx
16
+ 5. Client (`src/mailglyph/client.py`) — sync `MailGlyph` + async `AsyncMailGlyph`, accepts API key + config, exposes `.emails`, `.events`, `.contacts`, `.campaigns`, `.segments`
17
+ 6. Resources one at a time with pytest tests:
18
+ - Emails (send, verify) → tests
19
+ - Events (track with `pk_*` support, get_names) → tests
20
+ - Contacts (list, create, get, update, delete, count) → tests
21
+ - Campaigns (list, create, get, update, send, cancel, test, stats) → tests
22
+ - Segments (list, create, get, update, delete, list_contacts) → tests
23
+ 7. CI: [.github/workflows/ci.yml](cci:7://file:///Users/sharo/Library/CloudStorage/Dropbox/Projects/Plunk/plunk/.github/workflows/ci.yml:0:0-0:0), `release-please.yml`, `publish.yml`
24
+ 8. README with install + usage examples
25
+ 9. Run `pytest` — all tests must pass
26
+
27
+ ## Standards
28
+ - Python 3.9+ with type hints everywhere
29
+ - httpx for HTTP (sync + async with same codebase)
30
+ - Pydantic v2 for models with camelCase aliases
31
+ - pytest + respx for testing with mocked HTTP responses
32
+ - Snake_case method names (`list_contacts`, not `listContacts`)
33
+ - `from_` parameter name to avoid Python `from` keyword collision
34
+ - Conventional Commits for all commit messages
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ ## [2.0.0](https://github.com/MailGlyph/mailglyph-python/compare/v1.0.1...v2.0.0) (2026-03-09)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * Renames the SDK/package branding from Mailrify to MailGlyph.
9
+
10
+ ### Features
11
+
12
+ * Add `text` field to email sending parameters. ([cf7ae10](https://github.com/MailGlyph/mailglyph-python/commit/cf7ae10cf0bbcc4c79e80f38b75039a00973b367))
13
+ * Implement methods to add and remove contacts from static segments, along with supporting types and documentation. ([03b99ee](https://github.com/MailGlyph/mailglyph-python/commit/03b99ee87396e41c6bc5d758ae6bad8f0c5d4c33))
14
+
15
+
16
+ ### Code Refactoring
17
+
18
+ * rebrand Mailrify to MailGlyph ([431caad](https://github.com/MailGlyph/mailglyph-python/commit/431caadd0eedeed19e77c01ec453005bafe2d9dd))
19
+
20
+ ## [1.0.1](https://github.com/MailGlyph/mailglyph-python/compare/v1.0.0...v1.0.1) (2026-02-16)
21
+
22
+
23
+ ### Documentation
24
+
25
+ * Add CI, Release Please, and PyPI publish badges to the README. ([a02f30b](https://github.com/MailGlyph/mailglyph-python/commit/a02f30b6b5ece8a2c52534794ef1a1ed9304ac8a))
26
+
27
+ ## [1.0.0](https://github.com/MailGlyph/mailglyph-python/compare/v0.0.4...v1.0.0) (2026-02-16)
28
+
29
+
30
+ ### ⚠ BREAKING CHANGES
31
+
32
+ * complete API redesign, not compatible with 0.1.x
33
+
34
+ ### Features
35
+
36
+ * initial SDK implementation ([b067d32](https://github.com/MailGlyph/mailglyph-python/commit/b067d3288a77cfc120683bc8a34adb0c0f8dbe4d))
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * support pydantic type evaluation on python 3.9 ([9237800](https://github.com/MailGlyph/mailglyph-python/commit/9237800485f326acbe03d682f64ccc41883ccb4d))
42
+
43
+ ## Changelog
44
+
45
+ All notable changes to this project will be documented in this file.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) MailGlyph
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.4
2
+ Name: mailglyph
3
+ Version: 2.0.0
4
+ Summary: Official MailGlyph Python SDK
5
+ Project-URL: Homepage, https://github.com/MailGlyph/mailglyph-python
6
+ Project-URL: Repository, https://github.com/MailGlyph/mailglyph-python
7
+ Project-URL: Issues, https://github.com/MailGlyph/mailglyph-python/issues
8
+ Author: MailGlyph
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: email,mailglyph,sdk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: eval-type-backport>=0.2.0; python_version < '3.10'
24
+ Requires-Dist: httpx>=0.25
25
+ Requires-Dist: pydantic>=2.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.2; extra == 'dev'
28
+ Requires-Dist: mypy>=1.10; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
30
+ Requires-Dist: pytest>=7.4; extra == 'dev'
31
+ Requires-Dist: respx>=0.21; extra == 'dev'
32
+ Requires-Dist: ruff>=0.5; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # MailGlyph Python SDK
36
+
37
+ [![CI](https://github.com/MailGlyph/mailglyph-python/actions/workflows/ci.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/ci.yml)
38
+ [![Release Please](https://github.com/MailGlyph/mailglyph-python/actions/workflows/release-please.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/release-please.yml)
39
+ [![Publish to PyPI](https://github.com/MailGlyph/mailglyph-python/actions/workflows/publish.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/publish.yml)
40
+
41
+ Official Python SDK for the MailGlyph API.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install mailglyph
47
+ ```
48
+
49
+ ## Quick Start (Sync)
50
+
51
+ ```python
52
+ from mailglyph import MailGlyph
53
+
54
+ client = MailGlyph("sk_your_api_key")
55
+ ```
56
+
57
+ ## Quick Start (Async)
58
+
59
+ ```python
60
+ from mailglyph import AsyncMailGlyph
61
+
62
+ client = AsyncMailGlyph("sk_your_api_key")
63
+ ```
64
+
65
+ ## Emails
66
+
67
+ ```python
68
+ from mailglyph import MailGlyph
69
+
70
+ client = MailGlyph("sk_your_api_key")
71
+
72
+ result = client.emails.send(
73
+ to="user@example.com",
74
+ from_={"name": "My App", "email": "hello@myapp.com"},
75
+ subject="Welcome!",
76
+ body="<h1>Hello {{name}}</h1>",
77
+ text="Hello {{name}}",
78
+ data={"name": "John"},
79
+ )
80
+
81
+ # Omit `text` to let MailGlyph auto-generate plain text from HTML `body`.
82
+ html_only_result = client.emails.send(
83
+ to="user@example.com",
84
+ from_="hello@myapp.com",
85
+ subject="HTML Only",
86
+ body="<h1>Hello</h1><p>This will get text/plain fallback.</p>",
87
+ )
88
+
89
+ # Set text="" to opt out of text/plain generation.
90
+ opt_out_result = client.emails.send(
91
+ to="user@example.com",
92
+ from_="hello@myapp.com",
93
+ subject="No Plain Text Part",
94
+ body="<h1>Hello</h1>",
95
+ text="",
96
+ )
97
+
98
+ verification = client.emails.verify("user@example.com")
99
+ print(verification.valid, verification.is_random_input)
100
+ ```
101
+
102
+ ## Events
103
+
104
+ ```python
105
+ from mailglyph import MailGlyph
106
+
107
+ tracker = MailGlyph("pk_your_public_key")
108
+ tracker.events.track(
109
+ email="user@example.com",
110
+ event="purchase",
111
+ data={"product": "Premium", "amount": 99},
112
+ )
113
+
114
+ client = MailGlyph("sk_your_api_key")
115
+ names = client.events.get_names()
116
+ ```
117
+
118
+ ## Contacts
119
+
120
+ ```python
121
+ from mailglyph import MailGlyph
122
+
123
+ client = MailGlyph("sk_your_api_key")
124
+
125
+ contacts = client.contacts.list(limit=50)
126
+ contact = client.contacts.create(email="new@example.com", data={"plan": "premium"})
127
+ client.contacts.update(contact.id, subscribed=False)
128
+ client.contacts.delete(contact.id)
129
+ count = client.contacts.count()
130
+ ```
131
+
132
+ ## Segments
133
+
134
+ ```python
135
+ from mailglyph import MailGlyph
136
+
137
+ client = MailGlyph("sk_your_api_key")
138
+
139
+ segment = client.segments.create(
140
+ name="Premium Users",
141
+ condition={
142
+ "logic": "AND",
143
+ "groups": [
144
+ {
145
+ "filters": [
146
+ {"field": "data.plan", "operator": "equals", "value": "premium"}
147
+ ]
148
+ }
149
+ ],
150
+ },
151
+ track_membership=True,
152
+ )
153
+ members = client.segments.list_contacts(segment.id, page=1)
154
+ added = client.segments.add_members(segment.id, emails=["alice@example.com", "bob@example.com"])
155
+ removed = client.segments.remove_members(segment.id, emails=["bob@example.com"])
156
+ ```
157
+
158
+ ## Campaigns
159
+
160
+ ```python
161
+ from mailglyph import MailGlyph
162
+
163
+ client = MailGlyph("sk_your_api_key")
164
+
165
+ campaign = client.campaigns.create(
166
+ name="Product Launch",
167
+ subject="Introducing our new feature!",
168
+ body="<h1>Big news!</h1><p>Check out our latest feature.</p>",
169
+ from_email="hello@myapp.com",
170
+ audience_type="ALL",
171
+ )
172
+
173
+ campaigns_page = client.campaigns.list(page=1, page_size=20, status="DRAFT")
174
+ client.campaigns.send(campaign.id, scheduled_for="2026-03-01T10:00:00Z")
175
+ client.campaigns.test(campaign.id, email="preview@myapp.com")
176
+ stats = client.campaigns.stats(campaign.id)
177
+ client.campaigns.cancel(campaign.id)
178
+ ```
179
+
180
+ ## Async Example
181
+
182
+ ```python
183
+ import asyncio
184
+
185
+ from mailglyph import AsyncMailGlyph
186
+
187
+
188
+ async def main() -> None:
189
+ async with AsyncMailGlyph("sk_your_api_key") as client:
190
+ verification = await client.emails.verify("user@example.com")
191
+ print(verification.valid)
192
+
193
+
194
+ asyncio.run(main())
195
+ ```
196
+
197
+ ## Configuration
198
+
199
+ ```python
200
+ from mailglyph import MailGlyph
201
+
202
+ client = MailGlyph(
203
+ "sk_your_api_key",
204
+ base_url="https://api.mailglyph.com",
205
+ timeout=30.0,
206
+ max_retries=3,
207
+ )
208
+ ```
209
+
210
+ ## Development
211
+
212
+ ```bash
213
+ pip install -e .[dev]
214
+ ruff check .
215
+ mypy src/
216
+ pytest
217
+ hatch build
218
+ ```
@@ -0,0 +1,184 @@
1
+ # MailGlyph Python SDK
2
+
3
+ [![CI](https://github.com/MailGlyph/mailglyph-python/actions/workflows/ci.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/ci.yml)
4
+ [![Release Please](https://github.com/MailGlyph/mailglyph-python/actions/workflows/release-please.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/release-please.yml)
5
+ [![Publish to PyPI](https://github.com/MailGlyph/mailglyph-python/actions/workflows/publish.yml/badge.svg)](https://github.com/MailGlyph/mailglyph-python/actions/workflows/publish.yml)
6
+
7
+ Official Python SDK for the MailGlyph API.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install mailglyph
13
+ ```
14
+
15
+ ## Quick Start (Sync)
16
+
17
+ ```python
18
+ from mailglyph import MailGlyph
19
+
20
+ client = MailGlyph("sk_your_api_key")
21
+ ```
22
+
23
+ ## Quick Start (Async)
24
+
25
+ ```python
26
+ from mailglyph import AsyncMailGlyph
27
+
28
+ client = AsyncMailGlyph("sk_your_api_key")
29
+ ```
30
+
31
+ ## Emails
32
+
33
+ ```python
34
+ from mailglyph import MailGlyph
35
+
36
+ client = MailGlyph("sk_your_api_key")
37
+
38
+ result = client.emails.send(
39
+ to="user@example.com",
40
+ from_={"name": "My App", "email": "hello@myapp.com"},
41
+ subject="Welcome!",
42
+ body="<h1>Hello {{name}}</h1>",
43
+ text="Hello {{name}}",
44
+ data={"name": "John"},
45
+ )
46
+
47
+ # Omit `text` to let MailGlyph auto-generate plain text from HTML `body`.
48
+ html_only_result = client.emails.send(
49
+ to="user@example.com",
50
+ from_="hello@myapp.com",
51
+ subject="HTML Only",
52
+ body="<h1>Hello</h1><p>This will get text/plain fallback.</p>",
53
+ )
54
+
55
+ # Set text="" to opt out of text/plain generation.
56
+ opt_out_result = client.emails.send(
57
+ to="user@example.com",
58
+ from_="hello@myapp.com",
59
+ subject="No Plain Text Part",
60
+ body="<h1>Hello</h1>",
61
+ text="",
62
+ )
63
+
64
+ verification = client.emails.verify("user@example.com")
65
+ print(verification.valid, verification.is_random_input)
66
+ ```
67
+
68
+ ## Events
69
+
70
+ ```python
71
+ from mailglyph import MailGlyph
72
+
73
+ tracker = MailGlyph("pk_your_public_key")
74
+ tracker.events.track(
75
+ email="user@example.com",
76
+ event="purchase",
77
+ data={"product": "Premium", "amount": 99},
78
+ )
79
+
80
+ client = MailGlyph("sk_your_api_key")
81
+ names = client.events.get_names()
82
+ ```
83
+
84
+ ## Contacts
85
+
86
+ ```python
87
+ from mailglyph import MailGlyph
88
+
89
+ client = MailGlyph("sk_your_api_key")
90
+
91
+ contacts = client.contacts.list(limit=50)
92
+ contact = client.contacts.create(email="new@example.com", data={"plan": "premium"})
93
+ client.contacts.update(contact.id, subscribed=False)
94
+ client.contacts.delete(contact.id)
95
+ count = client.contacts.count()
96
+ ```
97
+
98
+ ## Segments
99
+
100
+ ```python
101
+ from mailglyph import MailGlyph
102
+
103
+ client = MailGlyph("sk_your_api_key")
104
+
105
+ segment = client.segments.create(
106
+ name="Premium Users",
107
+ condition={
108
+ "logic": "AND",
109
+ "groups": [
110
+ {
111
+ "filters": [
112
+ {"field": "data.plan", "operator": "equals", "value": "premium"}
113
+ ]
114
+ }
115
+ ],
116
+ },
117
+ track_membership=True,
118
+ )
119
+ members = client.segments.list_contacts(segment.id, page=1)
120
+ added = client.segments.add_members(segment.id, emails=["alice@example.com", "bob@example.com"])
121
+ removed = client.segments.remove_members(segment.id, emails=["bob@example.com"])
122
+ ```
123
+
124
+ ## Campaigns
125
+
126
+ ```python
127
+ from mailglyph import MailGlyph
128
+
129
+ client = MailGlyph("sk_your_api_key")
130
+
131
+ campaign = client.campaigns.create(
132
+ name="Product Launch",
133
+ subject="Introducing our new feature!",
134
+ body="<h1>Big news!</h1><p>Check out our latest feature.</p>",
135
+ from_email="hello@myapp.com",
136
+ audience_type="ALL",
137
+ )
138
+
139
+ campaigns_page = client.campaigns.list(page=1, page_size=20, status="DRAFT")
140
+ client.campaigns.send(campaign.id, scheduled_for="2026-03-01T10:00:00Z")
141
+ client.campaigns.test(campaign.id, email="preview@myapp.com")
142
+ stats = client.campaigns.stats(campaign.id)
143
+ client.campaigns.cancel(campaign.id)
144
+ ```
145
+
146
+ ## Async Example
147
+
148
+ ```python
149
+ import asyncio
150
+
151
+ from mailglyph import AsyncMailGlyph
152
+
153
+
154
+ async def main() -> None:
155
+ async with AsyncMailGlyph("sk_your_api_key") as client:
156
+ verification = await client.emails.verify("user@example.com")
157
+ print(verification.valid)
158
+
159
+
160
+ asyncio.run(main())
161
+ ```
162
+
163
+ ## Configuration
164
+
165
+ ```python
166
+ from mailglyph import MailGlyph
167
+
168
+ client = MailGlyph(
169
+ "sk_your_api_key",
170
+ base_url="https://api.mailglyph.com",
171
+ timeout=30.0,
172
+ max_retries=3,
173
+ )
174
+ ```
175
+
176
+ ## Development
177
+
178
+ ```bash
179
+ pip install -e .[dev]
180
+ ruff check .
181
+ mypy src/
182
+ pytest
183
+ hatch build
184
+ ```