Official Python SDK for the Lettermint email API.
pip install lettermintfrom lettermint import Lettermint
client = Lettermint(api_token="your-api-token")
response = (
client.email
.from_("sender@example.com")
.to("recipient@example.com")
.subject("Hello from Python!")
.html("<h1>Welcome!</h1>")
.text("Welcome!")
.send()
)
print(response["message_id"])from lettermint import AsyncLettermint
async with AsyncLettermint(api_token="your-api-token") as client:
response = await (
client.email
.from_("sender@example.com")
.to("recipient@example.com")
.subject("Hello from Python!")
.html("<h1>Welcome!</h1>")
.send()
)
print(response["message_id"])client.email.from_("sender@example.com").to(
"recipient1@example.com",
"recipient2@example.com"
).subject("Hello").send()client.email.from_("sender@example.com").to("recipient@example.com").cc(
"cc1@example.com",
"cc2@example.com"
).bcc("bcc@example.com").subject("Hello").send()client.email.from_("sender@example.com").to("recipient@example.com").reply_to(
"reply@example.com"
).subject("Hello").send()client.email.from_("John Doe <john@example.com>").to(
"Jane Doe <jane@example.com>"
).subject("Hello").send()import base64
# Read and encode your file
with open("document.pdf", "rb") as f:
content = base64.b64encode(f.read()).decode()
# Regular attachment
client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Your Document"
).attach("document.pdf", content).send()
# Inline attachment (for embedding in HTML)
client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Welcome"
).html('<img src="cid:logo@example.com">').attach(
"logo.png", logo_content, "logo@example.com"
).send()client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Hello"
).headers({"X-Custom-Header": "value"}).send()client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Hello"
).metadata({"campaign_id": "123", "user_id": "456"}).tag("welcome-campaign").send()client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Hello"
).route("my-route").send()Prevent duplicate sends when retrying failed requests:
client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Hello"
).idempotency_key("unique-request-id").send()Verify webhook signatures to ensure authenticity:
from lettermint import Webhook
# Create a webhook verifier
webhook = Webhook(secret="your-webhook-secret")
# Verify using headers (recommended)
payload = webhook.verify_headers(request.headers, request.body)
# Or verify using the signature directly
payload = webhook.verify(
payload=request.body,
signature=request.headers["X-Lettermint-Signature"],
)
print(payload["event"])For one-off verification:
from lettermint import Webhook
payload = Webhook.verify_signature(
payload=request.body,
signature=request.headers["X-Lettermint-Signature"],
secret="your-webhook-secret",
)Adjust the timestamp tolerance (default: 300 seconds):
webhook = Webhook(secret="your-webhook-secret", tolerance=600)from lettermint import Lettermint
from lettermint.exceptions import (
ValidationError,
ClientError,
HttpRequestError,
TimeoutError,
)
client = Lettermint(api_token="your-api-token")
try:
response = client.email.from_("sender@example.com").to("recipient@example.com").subject(
"Hello"
).send()
except ValidationError as e:
# 422 errors (e.g., daily limit exceeded)
print(f"Validation error: {e.error_type}")
print(f"Response: {e.response_body}")
except ClientError as e:
# 400 errors
print(f"Client error: {e}")
except TimeoutError as e:
# Request timeout
print(f"Timeout: {e}")
except HttpRequestError as e:
# Other HTTP errors
print(f"HTTP error {e.status_code}: {e}")from lettermint import Webhook
from lettermint.exceptions import (
InvalidSignatureError,
TimestampToleranceError,
JsonDecodeError,
WebhookVerificationError,
)
try:
payload = webhook.verify_headers(headers, body)
except InvalidSignatureError:
print("Invalid signature - request may be forged")
except TimestampToleranceError:
print("Timestamp too old - possible replay attack")
except JsonDecodeError:
print("Invalid JSON in payload")
except WebhookVerificationError as e:
print(f"Verification failed: {e}")client = Lettermint(
api_token="your-api-token",
base_url="https://custom.api.com/v1",
)client = Lettermint(
api_token="your-api-token",
timeout=60.0, # 60 seconds
)Both sync and async clients support context managers for proper resource cleanup:
# Sync
with Lettermint(api_token="your-api-token") as client:
client.email.from_("sender@example.com").to("recipient@example.com").send()
# Async
async with AsyncLettermint(api_token="your-api-token") as client:
await client.email.from_("sender@example.com").to("recipient@example.com").send()This SDK is fully typed with py.typed marker. You'll get full autocomplete and type checking in your IDE.
- Python 3.9+
- httpx
MIT