Python SDK

The official Python SDK for Veil Mail with sync and async support.

  • Sync and async clients via httpx
  • Full type hint support (PEP 484)
  • Typed error classes for error handling
  • Webhook signature verification utility
  • Python 3.9+ compatible

Installation

pip install veilmail

Quick Start

send.py
import veilmail

client = veilmail.VeilMail("veil_live_xxxxx")

# Send an email
email = client.emails.send(
    from_="hello@yourdomain.com",
    to="user@example.com",
    subject="Hello from Python!",
    html="<h1>Welcome!</h1>",
)

print(email["id"])   # email_xxxxx
print(email["status"])  # queued

Async Support

Use AsyncVeilMail for async/await support with asyncio.

async_send.py
import asyncio
import veilmail

async def main():
    async with veilmail.AsyncVeilMail("veil_live_xxxxx") as client:
        email = await client.emails.send(
            from_="hello@yourdomain.com",
            to="user@example.com",
            subject="Hello from async Python!",
            html="<h1>Welcome!</h1>",
        )
        print(email["id"])

asyncio.run(main())

Resources

The client exposes the same resources as the Node.js SDK:

ResourceDescription
client.emailsSend, list, get, cancel, update emails
client.domainsCreate, verify, list, delete domains
client.templatesCreate, update, list, delete templates
client.audiencesManage audiences and subscribers
client.campaignsCreate, schedule, send, pause campaigns
client.webhooksManage webhook endpoints
client.topicsManage subscription topics

Subscriber Management

subscribers.py
# Get a subscribers helper for an audience
subs = client.audiences.subscribers("audience_xxxxx")

# Add a subscriber
subscriber = subs.add(
    email="user@example.com",
    first_name="Alice",
    last_name="Smith",
    metadata={"plan": "premium"},
)

# List subscribers
result = subs.list(status="active", limit=50)
for sub in result["data"]:
    print(sub["email"])

# Import from CSV
result = subs.import_subscribers(
    csv_data="email,firstName\nuser1@example.com,Bob\nuser2@example.com,Carol"
)
print(f"Created: {result['created']}, Skipped: {result['skipped']}")

# Export as CSV
csv_data = subs.export(status="active")
with open("subscribers.csv", "w") as f:
    f.write(csv_data)

Error Handling

errors.py
import veilmail

client = veilmail.VeilMail("veil_live_xxxxx")

try:
    email = client.emails.send(
        from_="hello@yourdomain.com",
        to="user@example.com",
        subject="Hello",
        html="<p>Hi!</p>",
    )
except veilmail.RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except veilmail.PiiDetectedError as e:
    print(f"PII detected: {e.pii_types}")
except veilmail.ValidationError as e:
    print(f"Validation error: {e.message}")
except veilmail.AuthenticationError:
    print("Invalid API key")
except veilmail.VeilMailError as e:
    print(f"API error: {e.message} (code: {e.code})")

Webhook Verification

Use the built-in utility to verify webhook signatures:

webhook_handler.py
import json
import veilmail
from flask import Flask, request

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_xxxxx"

@app.post("/webhooks/veilmail")
def handle_webhook():
    payload = request.get_data(as_text=True)
    signature = request.headers.get("X-VeilMail-Signature", "")

    if not veilmail.verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
        return "Invalid signature", 401

    event = json.loads(payload)

    if event["type"] == "email.delivered":
        print(f"Delivered: {event['data']['emailId']}")
    elif event["type"] == "email.bounced":
        print(f"Bounced: {event['data']['emailId']}")

    return "OK", 200

Note on the from_ parameter

Since from is a reserved keyword in Python, the sender address parameter is named from_ (with a trailing underscore). The SDK automatically maps this to from in the API request.