Official Python SDK for the ShipMail API
Project description
ShipMail Python SDK
Official Python SDK for the ShipMail API. Provides both synchronous and asynchronous clients. Requires Python 3.10+.
Installation
pip install shipmail
Quick Start
from shipmail import ShipMail
client = ShipMail("sm_live_...")
# Create a domain
domain = client.domains.create({"name": "example.com"})
# Send an email
message = client.messages.send({
"mailbox_id": "mbx_...",
"to": [{"address": "user@example.com"}],
"subject": "Hello",
"body_text": "Hi there",
})
Async
from shipmail import AsyncShipMail
async with AsyncShipMail("sm_live_...") as client:
domain = await client.domains.create({"name": "example.com"})
message = await client.messages.send({
"mailbox_id": "mbx_...",
"to": [{"address": "user@example.com"}],
"subject": "Hello",
"body_text": "Hi there",
})
Configuration
from shipmail import ShipMail
client = ShipMail(
"sm_live_...",
base_url="https://shipmail.to/api/v1", # default
max_retries=2, # default, retries on 5xx and 429
timeout=30.0, # default, in seconds
)
Resources
Domains
domain = client.domains.create({"name": "example.com"})
domains = client.domains.list({"limit": 10})
domain = client.domains.get("dom_...")
updated = client.domains.update("dom_...", {"catch_all_mailbox_id": "mbx_..."})
client.domains.delete("dom_...")
result = client.domains.verify("dom_...")
Mailboxes
mailbox = client.mailboxes.create({
"domain_id": "dom_...",
"address": "hello",
"display_name": "Hello",
})
mailboxes = client.mailboxes.list({"domain_id": "dom_..."})
mailbox = client.mailboxes.get("mbx_...")
updated = client.mailboxes.update("mbx_...", {"display_name": "New Name"})
client.mailboxes.delete("mbx_...")
Messages
message = client.messages.send({
"mailbox_id": "mbx_...",
"to": [{"address": "user@example.com", "name": "User"}],
"cc": [{"address": "cc@example.com"}],
"subject": "Hello",
"body_html": "<p>Hi there</p>",
"body_text": "Hi there",
})
message = client.messages.get("msg_...")
Threads
threads = client.threads.list({"mailbox_id": "mbx_..."})
thread = client.threads.get("thd_...")
reply = client.threads.reply("thd_...", {
"body_text": "Thanks for your email",
"to": [{"address": "user@example.com"}],
})
Webhooks
webhook = client.webhooks.create({
"url": "https://example.com/webhook",
"events": ["message.received", "message.sent"],
"description": "My webhook",
})
# webhook["secret"] is only available at creation time
webhooks = client.webhooks.list()
webhook = client.webhooks.get("whk_...")
updated = client.webhooks.update("whk_...", {"active": False})
client.webhooks.delete("whk_...")
rotated = client.webhooks.rotate_secret("whk_...")
test = client.webhooks.test("whk_...")
deliveries = client.webhooks.list_deliveries("whk_...")
Status
status = client.status.get()
Pagination
List methods return a paginated response with cursor-based pagination:
page = client.domains.list({"limit": 10})
print(page["data"]) # list of domains
print(page["pagination"]) # {"next_cursor": ..., "has_more": ...}
# Fetch next page
if page["pagination"]["has_more"]:
next_page = client.domains.list({
"cursor": page["pagination"]["next_cursor"],
"limit": 10,
})
Auto-pagination iterates through all pages automatically:
for domain in client.domains.list_auto_paginating(limit=25):
print(domain["name"])
# Async
async for domain in client.domains.list_auto_paginating(limit=25):
print(domain["name"])
Webhook Verification
Verify incoming webhook signatures without instantiating a client:
from shipmail import verify_webhook, WebhookVerificationError
try:
event = verify_webhook(raw_body, headers, webhook_secret)
print(event["event_type"]) # e.g., "message.received"
print(event["data"])
except WebhookVerificationError:
# Invalid signature
pass
Error Handling
The SDK raises typed exceptions that map to API error responses:
from shipmail import (
ShipMailError,
AuthenticationError,
AuthorizationError,
ValidationError,
NotFoundError,
RateLimitError,
ConflictError,
InternalServerError,
APIConnectionError,
)
try:
client.domains.create({"name": ""})
except ValidationError as err:
print(err) # Error message
print(err.details) # Field-level validation errors
except RateLimitError as err:
print(err.retry_after) # Seconds to wait
except ShipMailError as err:
print(err.status) # HTTP status code
print(err.type) # Error type string
print(err.request_id) # Request ID for support
print(err.retryable) # Whether the request can be retried
Retries
The SDK automatically retries on 5xx errors and 429 (rate limit) responses with exponential backoff and jitter. Configure with max_retries (default: 2, meaning up to 3 total attempts).
client = ShipMail("sm_live_...", max_retries=0) # Disable retries
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shipmail-0.1.3.tar.gz.
File metadata
- Download URL: shipmail-0.1.3.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b805af7299b8d4e5325dd6f93c5ce3c675df8a7011a0bf0433cd17bee286ca3d
|
|
| MD5 |
6e9e247f80b2a58f722e1bacd0e56e92
|
|
| BLAKE2b-256 |
70b193ead7124e982ea24cccb4c4075c5d54ac66c8d4c60d02c08ce92364af03
|
Provenance
The following attestation bundles were made for shipmail-0.1.3.tar.gz:
Publisher:
release-please.yml on jcoulaud/ShipMail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shipmail-0.1.3.tar.gz -
Subject digest:
b805af7299b8d4e5325dd6f93c5ce3c675df8a7011a0bf0433cd17bee286ca3d - Sigstore transparency entry: 1108174662
- Sigstore integration time:
-
Permalink:
jcoulaud/ShipMail@ec5475730e47496ca735d21876cbc2f411e0dd2a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jcoulaud
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@ec5475730e47496ca735d21876cbc2f411e0dd2a -
Trigger Event:
push
-
Statement type:
File details
Details for the file shipmail-0.1.3-py3-none-any.whl.
File metadata
- Download URL: shipmail-0.1.3-py3-none-any.whl
- Upload date:
- Size: 22.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e2cb6267412c51a6abd20b2988bfcbd8c53c949f4c7b3c0e3eb35119d7e2226
|
|
| MD5 |
81cc3fd439c59bb46556306d93a84ded
|
|
| BLAKE2b-256 |
f9d188a6aebd0722965793279375eeea030790613875e994b0b349a97111bc00
|
Provenance
The following attestation bundles were made for shipmail-0.1.3-py3-none-any.whl:
Publisher:
release-please.yml on jcoulaud/ShipMail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shipmail-0.1.3-py3-none-any.whl -
Subject digest:
8e2cb6267412c51a6abd20b2988bfcbd8c53c949f4c7b3c0e3eb35119d7e2226 - Sigstore transparency entry: 1108174666
- Sigstore integration time:
-
Permalink:
jcoulaud/ShipMail@ec5475730e47496ca735d21876cbc2f411e0dd2a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jcoulaud
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@ec5475730e47496ca735d21876cbc2f411e0dd2a -
Trigger Event:
push
-
Statement type: