Taifa MailTaifa Mail Docs
SDKs

Python SDK

Install and use the official taifa-mail Python client to send email, manage domains, contacts, suppressions, templates, and webhooks.

The official Python client for Taifa Mail wraps the Emails API and every other Core resource in a small, typed surface. It is published as taifa-mail on PyPI, and the source lives in the taifa-mail-sdks repository.

Installation

pip install taifa-mail

The package has zero runtime dependencies (it uses only the Python standard library) and supports Python 3.8 and above.

Client setup

Create a client with your API key. Keys start with tfm_k_ and are passed as a bearer token on every request.

from taifa_mail import Taifa Mail
 
taifamail = TaifaMail(api_key="tfm_k_your_api_key")

The constructor accepts the following options:

OptionTypeDefaultDescription
api_keystrrequiredYour Taifa Mail API key. Must start with tfm_k_.
base_urlstrhttps://govconnect.keOverride the API host (for staging or self-hosted setups).
max_retriesint3Maximum attempts per request. Retries apply to 429 and 5xx responses.
timeoutfloat30.0Per-request timeout in seconds.
taifamail = TaifaMail(
    api_key="tfm_k_your_api_key",
    base_url="https://govconnect.ke",
    max_retries=5,
    timeout=60.0,
)

Keep your API key on the server. Never embed it in client-side code or commit it to source control. Load it from an environment variable instead.

Send an email

Pass a message dictionary to taifamail.emails.send. The from, to, cc, and bcc fields accept a bare email string, a {"email", "name"} dict, or a list of either.

from taifa_mail import Taifa Mail
 
taifamail = TaifaMail(api_key="tfm_k_your_api_key")
 
result = taifamail.emails.send({
    "from": "hello@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Your receipt",
    "html": "<p>Thanks for your order.</p>",
})
 
print(result["id"], result["status"])

You expose a clean from key. The SDK maps it to the API's wire field from_ for you, so you never write from_ yourself.

A richer send can set names, multiple recipients, a reply-to, tags, and a schedule. The send_at field accepts a datetime or an ISO 8601 string.

from datetime import datetime, timedelta
 
result = taifamail.emails.send({
    "from": {"email": "hello@yourdomain.com", "name": "Your Company"},
    "to": [
        {"email": "jane@example.com", "name": "Jane Doe"},
        "team@example.com",
    ],
    "cc": "manager@example.com",
    "subject": "Welcome aboard",
    "html": "<h1>Welcome!</h1>",
    "text": "Welcome!",
    "reply_to": "support@yourdomain.com",
    "headers": {"X-Campaign": "onboarding"},
    "tags": ["onboarding"],
    "send_at": datetime.utcnow() + timedelta(hours=1),
})

The send returns a result dict shaped like this:

{
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "status": "queued",
    "message_id": "<uuid@govconnect.ke>",
    "rejection_reason": None,
}

Emails

The taifamail.emails resource covers sending, lookups, search, scheduling, and inspection.

# Send a batch (one dict per email). Starter plan and above.
taifamail.emails.send_batch([
    {"from": "hello@yourdomain.com", "to": "a@example.com", "subject": "Hi", "html": "<p>1</p>"},
    {"from": "hello@yourdomain.com", "to": "b@example.com", "subject": "Hi", "html": "<p>2</p>"},
])
 
# Dry-run a send without delivering it.
check = taifamail.emails.validate({
    "from": "hello@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Test",
    "html": "<p>Test</p>",
})
print(check["valid"], check["can_send"])
 
# List recent emails (zero-based paging).
emails = taifamail.emails.list(status="delivered", page=0, limit=20)
 
# Fetch one email with its bodies and events.
email = taifamail.emails.get("a1b2c3d4-5678-90ab-cdef-1234567890ab")
 
# Event timeline for one email.
events = taifamail.emails.events("a1b2c3d4-5678-90ab-cdef-1234567890ab")
 
# Re-send a bounced, rejected, or failed email.
taifamail.emails.retry("a1b2c3d4-5678-90ab-cdef-1234567890ab")
 
# Search with inline tokens (to:, from:, status:, domain:, tag:).
hits = taifamail.emails.search(q="welcome status:delivered")
 
# Schedule management.
scheduled = taifamail.emails.list_scheduled()
taifamail.emails.cancel_scheduled("b2c3d4e5-6789-01bc-defg-2345678901bc")
taifamail.emails.send_scheduled_now("b2c3d4e5-6789-01bc-defg-2345678901bc")
 
# Poll for status changes since a timestamp (datetime or ISO string).
updated = taifamail.emails.updates("2026-04-06T10:00:00Z")
 
# Saved searches.
saved = taifamail.emails.get_saved_searches()
taifamail.emails.set_saved_searches(saved)

Domains

The taifamail.domains resource registers, verifies, inspects, and transfers sending domains.

# Register a domain. The response includes the DNS records to publish.
domain = taifamail.domains.create("yourdomain.com")
 
# List and fetch.
domains = taifamail.domains.list()
domain = taifamail.domains.get(domain["id"])
 
# Re-check DNS and verify.
taifamail.domains.verify(domain["id"])
 
# Live DNS checks and diagnostics.
health = taifamail.domains.health(domain["id"])
diagnosis = taifamail.domains.diagnose(domain["id"])
mx = taifamail.domains.mx_status(domain["id"])
records = taifamail.domains.published_records(domain["id"])
 
# Rotate the DKIM key.
taifamail.domains.rotate_dkim(domain["id"])
 
# Transfer to another Taifa Mail account.
taifamail.domains.transfer(domain["id"], target_email="new-owner@example.com", note="handover")
 
# Availability checks.
taifamail.domains.check_availability("newdomain.com")
taifamail.domains.check("yourdomain.com")
 
# Delete.
taifamail.domains.delete(domain["id"])

Contacts

The taifamail.contacts resource manages subscriber lists, their contacts, CSV imports, and templated bulk sends.

# Lists.
lists = taifamail.contacts.list_lists()
contact_list = taifamail.contacts.create_list(name="Newsletter", description="Monthly updates")
detail = taifamail.contacts.get_list(contact_list["id"], page=0, limit=50)
taifamail.contacts.update_list(contact_list["id"], name="Monthly Newsletter")
taifamail.contacts.delete_list(contact_list["id"])
 
# Contacts.
contact = taifamail.contacts.add_contact(
    contact_list["id"],
    email="subscriber@example.com",
    name="Sam",
    metadata={"plan": "pro"},
)
taifamail.contacts.remove_contact(contact_list["id"], contact["id"])
 
# Import from a CSV file (multipart upload; email column auto-detected).
with open("contacts.csv", "rb") as f:
    taifamail.contacts.upload_csv(contact_list["id"], f.read(), filename="contacts.csv")
 
# Send a templated email to every contact in the list.
# Subject/html/text may use {{email}}, {{name}}, and {{metadata_key}} placeholders.
taifamail.contacts.bulk_send(
    contact_list["id"],
    sender_address_id="sender-uuid",
    subject="Hello {{name}}",
    html="<p>Hi {{name}}</p>",
)

Suppressions

The taifamail.suppressions resource manages the do-not-send list. The list returns a paginated envelope of {items, total, page, limit}.

# Paginated list with optional search.
page = taifamail.suppressions.list(page=0, limit=50, search="example.com")
for item in page["items"]:
    print(item)
 
# Suppress a single address.
taifamail.suppressions.add(email="bounced@example.com", reason="manual")
 
# Bulk import from a file (one email per line).
with open("suppressions.txt", "rb") as f:
    taifamail.suppressions.bulk_upload(f.read(), filename="suppressions.txt")
 
# Remove a suppression.
taifamail.suppressions.remove("suppression-uuid")

Templates

The taifamail.templates resource manages reusable email templates. Available on the Starter plan and above.

templates = taifamail.templates.list()
 
template = taifamail.templates.create(
    name="Receipt",
    subject="Your receipt",
    html="<p>Thanks, {{name}}.</p>",
)
 
taifamail.templates.get(template["id"])
taifamail.templates.update(template["id"], subject="Your updated receipt")
taifamail.templates.duplicate(template["id"])
taifamail.templates.delete(template["id"])

The html and text arguments map to the wire fields html_body and text_body. Template variables are derived server-side from {{name}} placeholders, so you do not pass them.

Webhooks

The taifamail.webhooks resource manages event subscriptions and inspects deliveries.

# Create a webhook. The signing secret is generated and returned.
hook = taifamail.webhooks.create(
    url="https://your-app.example.com/hooks/taifamail",
    events=["email.delivered", "email.bounced"],
)
 
# List and update.
hooks = taifamail.webhooks.list()
taifamail.webhooks.update(hook["id"], is_active=False)
 
# Send a sample email.delivered delivery to test the endpoint.
taifamail.webhooks.test(hook["id"])
 
# Inspect delivery attempts (paginated envelope).
deliveries = taifamail.webhooks.list_deliveries(hook["id"], page=0, limit=20)
delivery = taifamail.webhooks.get_delivery(hook["id"], "delivery-uuid")
 
# Delete.
taifamail.webhooks.delete(hook["id"])

Error handling

Any non-2xx response, or a transport failure that survives every retry, raises TaifaMailError. Inspect its attributes to branch on specific failures.

AttributeTypeDescription
statusintHTTP status code. 0 indicates a transport or network failure.
codestr or NoneMachine-readable error code from the API body, when present.
messagestrHuman-readable message (the exception's string value).
detailanyThe raw parsed response body, for debugging.
from taifa_mail import Taifa Mail, TaifaMailError
 
taifamail = TaifaMail(api_key="tfm_k_your_api_key")
 
try:
    taifamail.emails.send({
        "from": "hello@yourdomain.com",
        "to": "customer@example.com",
        "subject": "Your receipt",
        "html": "<p>Thanks for your order.</p>",
    })
except TaifaMailError as e:
    print(f"status={e.status} code={e.code} message={e}")
    if e.status == 422:
        # Sender not registered, or domain not verified.
        ...

Configuration

The client tunes its network behaviour through three constructor options.

  • Retries. Requests that return 429 (rate limited) or any 5xx are retried automatically, up to max_retries attempts (default 3). Backoff is exponential, and a Retry-After header is honoured when present. Uploads are not retried, because they are not idempotent.
  • Timeout. Each request is bounded by timeout seconds (default 30.0). A timeout that exhausts all retries raises TaifaMailError with status set to 0.
  • Base URL. Point base_url at a staging or self-hosted host. It defaults to https://govconnect.ke and trailing slashes are trimmed.
taifamail = TaifaMail(
    api_key="tfm_k_your_api_key",
    base_url="https://staging.govconnect.ke",
    max_retries=5,
    timeout=45.0,
)

Next steps

  • SDK overview - compare the Python client with the SDKs for other languages.
  • Emails API reference - the underlying REST endpoints, request bodies, and response shapes.

On this page