Skip to main content

1. Installation

Install the SDK via pip:
pip install lettermint
Requires Python 3.9 or higher.

2. Send your first email

Initialize the client with your API token:
import os
from lettermint import Lettermint

client = Lettermint(api_token=os.environ.get("LETTERMINT_API_TOKEN"))
Send your first email:
response = (
    client.email
    .from_("John Doe <[email protected]>")
    .to("[email protected]")
    .subject("Hello from Lettermint")
    .text("This is a test email sent using the Lettermint Python SDK.")
    .send()
)

print(f"Email sent with ID: {response['message_id']}")

3. Email Features

Basic Email

Send a simple text or HTML email:
response = (
    client.email
    .from_("John Doe <[email protected]>")
    .to("[email protected]")
    .subject("Your account is ready!")
    .html("<h1>Welcome!</h1><p>Thanks for signing up.</p>")
    .text("Welcome! Thanks for signing up.")
    .send()
)

Multiple Recipients

Send to multiple recipients using CC and BCC:
response = (
    client.email
    .from_("John Doe <[email protected]>")
    .to("[email protected]", "[email protected]")
    .cc("[email protected]")
    .bcc("[email protected]")
    .subject("Monthly Newsletter")
    .html("<h1>This Month's Updates</h1>")
    .send()
)

Custom Headers and Reply-To

Add custom headers and set reply-to addresses:
response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .reply_to("[email protected]")
    .subject("Support Ticket #12345")
    .headers({
        "X-Priority": "1",
        "X-Ticket-ID": "12345"
    })
    .html("<p>Your support ticket has been updated.</p>")
    .send()
)

Metadata

Add metadata for tracking and webhook payloads:
response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("Order Confirmation")
    .metadata({
        "order_id": "12345",
        "customer_id": "cust_789",
        "campaign": "order_confirmation"
    })
    .html("<p>Your order has been confirmed.</p>")
    .send()
)
Metadata is included in webhook payloads but not added to the actual email headers. Use it for tracking and analytics purposes.

Tags

Categorize emails for filtering and analytics:
response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("System Alert")
    .tag("system-alerts")
    .html("<p>Critical system alert detected.</p>")
    .send()
)
One tag per message. Tags can contain letters, numbers, hyphens, underscores, and spaces (max 255 characters). See Tags documentation for more details.

Route Selection

Direct emails to specific routes within your project:
response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("Welcome!")
    .route("transactional")
    .html("<p>Welcome to our platform.</p>")
    .send()
)

File Attachments

Attach files to your emails:
import base64

# Read and encode file
with open("/path/to/document.pdf", "rb") as f:
    encoded_content = base64.b64encode(f.read()).decode()

response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("Your Invoice")
    .html("<p>Please find your invoice attached.</p>")
    .attach("invoice.pdf", encoded_content)
    .send()
)

Inline Images

Embed images directly in your HTML using Content-ID:
import base64

with open("/path/to/logo.png", "rb") as f:
    encoded_logo = base64.b64encode(f.read()).decode()

response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("Welcome to Our Platform")
    .html('<p>Welcome!</p><img src="cid:[email protected]" alt="Logo">')
    .attach("logo.png", encoded_logo, "[email protected]")
    .send()
)

Idempotency

Prevent duplicate emails with idempotency keys:
response = (
    client.email
    .from_("[email protected]")
    .to("[email protected]")
    .subject("Order Confirmation")
    .html("<p>Your order has been confirmed.</p>")
    .idempotency_key("order-12345-confirmation")
    .send()
)
Use a unique key per logical email (e.g., combining order ID + email type). Retrying with the same key won’t send duplicate emails.

4. Async Support

The SDK provides an async client for use with asyncio:
import asyncio
import os
from lettermint import AsyncLettermint

async def send_email():
    async with AsyncLettermint(api_token=os.environ.get("LETTERMINT_API_TOKEN")) as client:
        response = await (
            client.email
            .from_("John Doe <[email protected]>")
            .to("[email protected]")
            .subject("Hello from Lettermint")
            .text("This is a test email.")
            .send()
        )
        print(f"Email sent with ID: {response['message_id']}")

asyncio.run(send_email())
Use the async client in FastAPI, Starlette, or other async frameworks for better performance.

5. Client Configuration

Customize the client with optional parameters:
client = Lettermint(
    api_token=os.environ.get("LETTERMINT_API_TOKEN"),
    base_url="https://api.lettermint.co/v1",  # Custom API URL
    timeout=60.0,  # Request timeout in seconds
)
Use the client as a context manager for automatic resource cleanup:
with Lettermint(api_token=os.environ.get("LETTERMINT_API_TOKEN")) as client:
    response = (
        client.email
        .from_("[email protected]")
        .to("[email protected]")
        .subject("Test")
        .text("Hello!")
        .send()
    )

6. Response

response = (
    client.email
    .from_("John Doe <[email protected]>")
    .to("[email protected]")
    .subject("Test")
    .text("Hello!")
    .send()
)

print(response["message_id"])  # Unique email ID

7. Error Handling

Handle errors with specific exception types:
from lettermint import Lettermint
from lettermint.exceptions import (
    ValidationError,
    ClientError,
    TimeoutError,
    HttpRequestError,
)

client = Lettermint(api_token=os.environ.get("LETTERMINT_API_TOKEN"))

try:
    response = (
        client.email
        .from_("[email protected]")
        .to("[email protected]")
        .subject("Test")
        .text("Hello!")
        .send()
    )
except ValidationError as e:
    # 422 errors (invalid parameters, daily limit exceeded, etc.)
    print(f"Validation error: {e.error_type}")
except ClientError as e:
    # 400 errors (bad request)
    print(f"Client error: {e}")
except TimeoutError as e:
    # Request timed out
    print(f"Timeout: {e}")
except HttpRequestError as e:
    # Other HTTP errors
    print(f"HTTP error {e.status_code}: {e}")

Next Steps

GitHub Repository

Find the complete source code, report issues, or contribute on GitHub.