Python SDK
pip install vaartixThe current version is 0.2.0. Works with Python 3.10 to 3.14, with no dependencies and full type hints. The package is on PyPI and the source is on GitHub at vaartix-mail/vaartix-python. Step-by-step guide: Send email from Django.
Using an AI assistant such as Claude or Cursor? The MCP server lets it send email and look up delivery status through the same API, without writing code.
Send an email
Section titled “Send an email”from vaartix import Vaartix
vaartix = Vaartix() # reads the VAARTIX_API_KEY environment variable
email = vaartix.emails.send( { "subject": "Hello from Vaartix", "html": "<strong>It works!</strong>", })print(email["id"]) # em_...Emails are plain dicts because from is a Python keyword. Keys can be snake_case
(reply_to, scheduled_at) or the API’s camelCase (replyTo, scheduledAt). Responses are the
API’s JSON as dicts, exactly as in the API reference.
Methods
Section titled “Methods”# Retry safely: the same key within 24 hours returns the first email instead of sending twice.vaartix.emails.send(email, idempotency_key=f"welcome-{user.id}")
# Send later (up to 30 days ahead), and cancel if plans change.scheduled = vaartix.emails.send({**email, "scheduled_at": "2026-11-01T09:00:00+05:30"})vaartix.emails.cancel(scheduled["id"])
# Up to 100 emails in one request.vaartix.batch.send([email_1, email_2])
# Look up an email and its delivery events, or list recent bounces.vaartix.emails.get("em_...")vaartix.emails.list(status="bounced", days=7)No domain yet? Send from any address at test.vaartix.com to delivered@, bounced@ or
[email protected] to simulate what happens:
vaartix.emails.send( { "subject": "Hello", "text": "It works!", })Django
Section titled “Django”Since vaartix 0.2.0, you can send all of Django’s email through Vaartix, including send_mail,
EmailMessage and built-in emails such as password resets:
pip install "vaartix[django]"VAARTIX_API_KEY = os.environ["VAARTIX_API_KEY"]
# Django 6.1 and newerMAILERS = {"default": {"BACKEND": "vaartix.django.EmailBackend"}}# Django 4.2 to 6.0EMAIL_BACKEND = "vaartix.django.EmailBackend"With MAILERS you can also pass the key as an option instead:
{"BACKEND": "vaartix.django.EmailBackend", "OPTIONS": {"api_key": "vx_live_..."}}.
from django.core.mail import EmailMultiAlternatives
message.attach_alternative("<p>Thanks!</p>", "text/html")message.tags = [{"name": "type", "value": "order"}] # optionalmessage.send()print(message.vaartix_id) # em_...HTML alternatives, attachments, inline images (Content-ID), cc, bcc, reply-to and custom
headers are all supported. Errors raise VaartixError unless you pass fail_silently=True.
Errors
Section titled “Errors”API and network errors raise VaartixError:
from vaartix import VaartixError
try: vaartix.emails.send(email)except VaartixError as err: print(err.type, err.status_code, err.message) # e.g. rate_limited 429 Too many requests...err.type is a stable code; the full list is in Errors. Network failures
have type == "network_error" and status_code is None.
Webhooks
Section titled “Webhooks”Check that a webhook request really came from Vaartix before trusting it. verify_webhook() checks
the signature and timestamp (Standard Webhooks) and returns the
parsed event. Pass the raw body, not parsed JSON.
import os
from flask import Flask, requestfrom vaartix import verify_webhook, WebhookVerificationError
app = Flask(__name__)
@app.post("/webhooks/vaartix")def vaartix_webhook(): try: event = verify_webhook( request.get_data(), # raw bytes, not request.json request.headers, os.environ["VAARTIX_WEBHOOK_SECRET"], ) except WebhookVerificationError: return "", 400 if event["type"] == "email.bounced": ... # stop emailing event["data"]["recipient"] return "", 200Django
Section titled “Django”In Django, use request.body and request.headers:
import os
from django.http import HttpResponsefrom django.views.decorators.csrf import csrf_exemptfrom django.views.decorators.http import require_POSTfrom vaartix import verify_webhook, WebhookVerificationError
@csrf_exempt # Vaartix signs the request instead@require_POSTdef vaartix_webhook(request): try: event = verify_webhook( request.body, # raw bytes request.headers, os.environ["VAARTIX_WEBHOOK_SECRET"], ) except WebhookVerificationError: return HttpResponse(status=400) if event["type"] == "email.bounced": ... # stop emailing event["data"]["recipient"] return HttpResponse(status=200)Manage endpoints with vaartix.webhooks.create(url=..., events=[...]), list(), get(),
update(), remove(), rotate_secret(), deliveries() and retry_delivery(). See
Webhooks for the events and how retries work.