Taifa MailTaifa Mail Docs
SDKs

PHP SDK

Send email, manage domains, contacts, suppressions, templates, and webhooks from PHP with the official Taifa Mail SDK.

The official PHP SDK for Taifa Mail. It wraps the Mailer REST API with a small, typed client: bearer authentication, JSON encode/decode, the from to from_ wire mapping, multipart uploads, and automatic retries on 429 and 5xx responses are all handled for you.

Methods return plain associative arrays decoded straight from the API response, so you work with the same field names documented in the API reference.


Installation

Install with Composer:

composer require taifamail/sdk

Requirements:

  • PHP 8.1 or later
  • Guzzle (pulled in automatically as a dependency)

Client setup

Create a client with your API key. Keys start with tfm_k_ and are passed as a bearer token on every request. Read it from the environment rather than hardcoding it.

<?php
 
require 'vendor/autoload.php';
 
use TaifaMail\Sdk\Client;
 
$taifamail = new Client(getenv('TAIFA_MAIL_API_KEY'));

The constructor takes an optional second array $options argument:

OptionTypeDefaultDescription
baseUrlstringhttps://govconnect.keAPI base URL. Override for staging.
maxRetriesint3Attempts for retryable (429/5xx) responses.
timeoutfloat|int30Per-request timeout in seconds.
httpGuzzleHttp\ClientInterfacenew Guzzle clientCustom HTTP client, mainly for testing.
$taifamail = new Client(getenv('TAIFA_MAIL_API_KEY'), [
    'baseUrl' => 'https://govconnect.ke',
    'maxRetries' => 5,
    'timeout' => 60,
]);

The client exposes one property per resource group: $taifamail->emails, $taifamail->domains, $taifamail->contacts, $taifamail->suppressions, $taifamail->templates, and $taifamail->webhooks.


Send an email

Pass an associative array to emails->send(). The address fields (from, to, cc, bcc, replyTo) each accept either a bare string or an ['email' => ..., 'name' => ...] array. A bare string is shorthand for ['email' => $string]. The to, cc, and bcc fields also accept a list of addresses.

<?php
 
require 'vendor/autoload.php';
 
use TaifaMail\Sdk\Client;
 
$taifamail = new Client(getenv('TAIFA_MAIL_API_KEY'));
 
$result = $taifamail->emails->send([
    'from' => 'hello@yourdomain.com',
    'to' => 'customer@example.com',
    'subject' => 'Your receipt',
    'html' => '<h1>Thanks for your order</h1><p>Your receipt is attached.</p>',
    'text' => 'Thanks for your order. Your receipt is attached.',
]);
 
echo $result['id'];      // "a1b2c3d4-5678-90ab-cdef-1234567890ab"
echo $result['status'];  // "queued"

A fuller example using named addresses, multiple recipients, and scheduling:

$result = $taifamail->emails->send([
    'from' => ['email' => 'hello@yourdomain.com', 'name' => 'Your Company'],
    'to' => [
        ['email' => 'jane@example.com', 'name' => 'Jane Doe'],
        'john@example.com',
    ],
    'cc' => 'team@yourdomain.com',
    'replyTo' => ['email' => 'support@yourdomain.com', 'name' => 'Support'],
    'subject' => 'Welcome aboard',
    'html' => '<h1>Welcome!</h1>',
    'tags' => ['onboarding'],
    'headers' => ['X-Campaign' => 'spring'],
    'sendAt' => '2026-07-01T09:00:00Z',
]);

The SDK maps the clean from key to the API's from_ field for you, and turns string addresses into address objects. You never write from_ directly. Scheduling with sendAt requires the Starter plan or above.

The response is an associative array with id, status, message_id, and rejection_reason.


Emails

Send, look up, search, schedule, and inspect messages via $taifamail->emails.

// Send a batch (bare array of messages; Starter plan and above)
$batch = $taifamail->emails->sendBatch([
    ['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 validation: would this send, without actually sending?
$check = $taifamail->emails->validate([
    'from' => 'hello@yourdomain.com',
    'to' => 'customer@example.com',
    'subject' => 'Test',
    'html' => '<p>Test</p>',
]);
 
// List recent emails (zero-based page)
$emails = $taifamail->emails->list(['status' => 'delivered', 'page' => 0, 'limit' => 20]);
 
// Fetch one email with its bodies and event timeline
$email = $taifamail->emails->get('a1b2c3d4-5678-90ab-cdef-1234567890ab');
 
// Event timeline only
$events = $taifamail->emails->events('a1b2c3d4-5678-90ab-cdef-1234567890ab');
 
// Re-send a bounced, rejected, or failed email
$retry = $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', 'limit' => 50]);
 
// Scheduled email management
$scheduled = $taifamail->emails->listScheduled();
$taifamail->emails->cancelScheduled('b2c3d4e5-...');
$taifamail->emails->sendScheduledNow('b2c3d4e5-...');
 
// Poll for status changes since a timestamp (max 50 rows)
$updated = $taifamail->emails->updates('2026-06-13T10:00:00Z');
 
// Saved searches
$searches = $taifamail->emails->getSavedSearches();
$taifamail->emails->setSavedSearches($searches);

Domains

Register, verify, inspect, and transfer sending domains via $taifamail->domains.

// List domains and their verification status
$domains = $taifamail->domains->list();
 
// Register a domain; the response carries the DNS records to publish
$domain = $taifamail->domains->create('yourdomain.com');
 
// Fetch, verify, delete
$domain = $taifamail->domains->get($domain['id']);
$taifamail->domains->verify($domain['id']);
$taifamail->domains->delete($domain['id']);
 
// Health and diagnostics
$health = $taifamail->domains->health($domain['id']);
$diagnosis = $taifamail->domains->diagnose($domain['id']);
$mx = $taifamail->domains->mxStatus($domain['id']);
$published = $taifamail->domains->publishedRecords($domain['id']);
 
// Rotate the DKIM key
$rotation = $taifamail->domains->rotateDkim($domain['id']);
 
// Transfer to another Taifa Mail account
$transfer = $taifamail->domains->transfer($domain['id'], [
    'targetEmail' => 'owner@otherteam.com',
    'note' => 'Handing over the marketing domain.',
]);
 
// Availability checks
$availability = $taifamail->domains->checkAvailability('yourdomain.com');
$exists = $taifamail->domains->check('yourdomain.com');

Contacts

Manage subscriber lists, their contacts, CSV imports, and templated bulk sends via $taifamail->contacts.

// Lists
$lists = $taifamail->contacts->listLists();
 
$list = $taifamail->contacts->createList([
    'name' => 'Newsletter',
    'description' => 'Monthly product news',
    'iconSeed' => 'taifa',
]);
 
$detail = $taifamail->contacts->getList($list['id'], ['page' => 0, 'limit' => 50]);
$taifamail->contacts->updateList($list['id'], ['name' => 'Product Newsletter']);
$taifamail->contacts->deleteList($list['id']);
 
// Contacts
$contact = $taifamail->contacts->addContact($list['id'], [
    'email' => 'subscriber@example.com',
    'name' => 'Sam Subscriber',
    'metadata' => ['plan' => 'pro'],
]);
$taifamail->contacts->removeContact($list['id'], $contact['id']);
 
// CSV import (header row required); send the raw file bytes
$csv = file_get_contents('subscribers.csv');
$import = $taifamail->contacts->uploadCsv($list['id'], $csv, 'subscribers.csv');
 
// Templated bulk send to the whole list
// Subject/html/text may use {{email}}, {{name}}, and {{metadata_key}} placeholders.
$send = $taifamail->contacts->bulkSend($list['id'], [
    'senderAddressId' => 'sender-uuid',
    'subject' => 'Hello {{name}}',
    'html' => '<p>Hi {{name}}, here is this month\'s update.</p>',
    'tags' => ['newsletter'],
]);

The list id is injected as contact_list_id automatically, so you do not set it in the bulkSend array. The senderAddressId maps to the wire field sender_address_id.


Suppressions

Manage the do-not-send list via $taifamail->suppressions.

// List suppressed addresses (paginated envelope: items, total, page, limit)
$page = $taifamail->suppressions->list(['page' => 0, 'limit' => 50, 'search' => 'example.com']);
foreach ($page['items'] as $entry) {
    echo $entry['email_address'], PHP_EOL;
}
 
// Suppress one address; SDK `email` maps to the wire field `email_address`
$taifamail->suppressions->add(['email' => 'bounce@example.com', 'reason' => 'manual']);
 
// Bulk import from a file, one email per line (Starter plan and above)
$txt = file_get_contents('suppressions.txt');
$taifamail->suppressions->bulkUpload($txt, 'suppressions.txt');
 
// Remove by id
$taifamail->suppressions->remove('suppression-uuid');

Templates

Manage reusable email templates via $taifamail->templates. Available on the Starter plan and above.

$templates = $taifamail->templates->list();
 
// The SDK's `html`/`text` map to the wire fields `html_body`/`text_body`.
// `variables` are derived server-side from {{name}} placeholders, so you do not pass them.
$template = $taifamail->templates->create([
    'name' => 'Receipt',
    'subject' => 'Your receipt, {{name}}',
    'html' => '<h1>Thanks {{name}}</h1>',
    'text' => 'Thanks {{name}}',
]);
 
$template = $taifamail->templates->get($template['id']);
$taifamail->templates->update($template['id'], ['subject' => 'Your order receipt']);
$taifamail->templates->duplicate($template['id']);
$taifamail->templates->delete($template['id']);

Webhooks

Manage event subscriptions and inspect deliveries via $taifamail->webhooks.

$webhooks = $taifamail->webhooks->list();
 
// Create; the signing `secret` is generated and returned in the response
$webhook = $taifamail->webhooks->create([
    'url' => 'https://example.com/hooks/taifamail',
    'events' => ['email.delivered', 'email.bounced'],
]);
 
// Update (partial); SDK `isActive` maps to the wire field `is_active`
$taifamail->webhooks->update($webhook['id'], ['isActive' => false]);
 
// Send a sample email.delivered delivery to test the endpoint
$taifamail->webhooks->test($webhook['id']);
 
// Inspect deliveries (paginated envelope: items, total, page, limit)
$deliveries = $taifamail->webhooks->listDeliveries($webhook['id'], ['page' => 0, 'limit' => 20]);
$delivery = $taifamail->webhooks->getDelivery($webhook['id'], $deliveries['items'][0]['id']);
 
$taifamail->webhooks->delete($webhook['id']);

Error handling

Every non-2xx response, and any transport failure that survives all retries, throws TaifaMail\Sdk\TaifaMailException. Inspect getStatus() for the HTTP status code and getCode() for the API's string error code.

use TaifaMail\Sdk\TaifaMailException;
 
try {
    $taifamail->emails->send([
        'from' => 'hello@unverified.com',
        'to' => 'customer@example.com',
        'subject' => 'Hi',
        'html' => '<p>Hello</p>',
    ]);
} catch (TaifaMailException $e) {
    $e->getStatus();   // int HTTP status, e.g. 422. 0 means a network/transport failure.
    $e->getCode();     // ?string API error code, e.g. "unverified_sender"
    $e->getMessage();  // human-readable message
    $e->getDetail();   // mixed: the raw parsed response body, for debugging
}

getStatus() returns 0 for a network or transport failure where no HTTP response was received. Retries on 429 and 5xx (honouring Retry-After) happen automatically before an exception is thrown, so by the time you catch one, those have already been exhausted. 4xx responses other than 429 are never retried.


Configuration

All knobs are passed through the second constructor argument.

$taifamail = new Client(getenv('TAIFA_MAIL_API_KEY'), [
    // Retry 429 and 5xx responses up to this many attempts (default 3).
    'maxRetries' => 5,
 
    // Per-request timeout in seconds (default 30).
    'timeout' => 60,
 
    // Point at a different environment (default https://govconnect.ke).
    'baseUrl' => 'https://staging.govconnect.ke',
]);

Retry behaviour: the transport retries 429 and 5xx responses with exponential backoff, honouring the Retry-After header when the server sends one. Multipart uploads (CSV and suppression imports) are never retried because they are not idempotent.

You can also inject a preconfigured Guzzle client via the http option, which is useful for testing or for sharing connection pools and middleware.


Next steps

On this page