Taifa MailTaifa Mail Docs
Sending Emails

Send via REST API

Send transactional and marketing emails programmatically using the Taifa Mail REST API.

The REST API is the most flexible way to send email through Taifa Mail. All requests go to https://govconnect.ke/v1/ and require an API key.

Authentication

Include your API key in the Authorization header on every request. API keys are prefixed with tfm_k_:

Authorization: Bearer tfm_k_YOUR_API_KEY

Generate API keys at Settings -> API Keys -> Create Key.

POST /v1/emails/

Send a single email. Note the trailing slash on the path.

Request body

FieldTypeRequiredDescription
from_objectYesSender address. Must be a registered sender on a verified domain.
from_.emailstringYesSender email address.
from_.namestringNoSender display name.
toarrayYesArray of recipient {email, name} objects. At least one required.
to[].emailstringYesRecipient email address.
to[].namestringNoRecipient display name.
subjectstringYesEmail subject line.
htmlstringNoHTML body. At least one of html or text is required.
textstringNoPlain text body. At least one of html or text is required.
ccarrayNoArray of {email, name} objects for CC recipients.
bccarrayNoArray of {email, name} objects for BCC recipients.
reply_toobjectNo{email, name} object for the Reply-To header.
headersobjectNoKey-value pairs of custom email headers.
tagsarrayNoArray of strings for categorization and filtering.
send_atstringNoISO 8601 datetime to schedule delivery. Omit to send immediately. See Scheduling.
attachmentsarrayNoArray of attachment objects (see below).

Attachments

Each attachment is an object with the file body base64-encoded:

FieldTypeRequiredDescription
filenamestringYesFile name. Must not contain path separators (/, \) or NUL.
content_base64stringYesFile body as base64. No data: URL prefix.
content_typestringNoMIME type. Defaults to application/octet-stream.

Each file is capped at 24 MiB, and the combined size of all attachments is also capped at 24 MiB. Oversized attachments return 413.

Example: cURL

curl -X POST https://govconnect.ke/v1/emails/ \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_": {
      "email": "hello@yourdomain.com",
      "name": "Your Company"
    },
    "to": [
      {
        "email": "customer@example.com",
        "name": "Jane Doe"
      }
    ],
    "subject": "Your order has shipped",
    "html": "<h1>Order Shipped</h1><p>Your package is on the way.</p>",
    "text": "Order Shipped\n\nYour package is on the way.",
    "tags": ["transactional", "order-updates"]
  }'

Example: Node.js (fetch)

const response = await fetch("https://govconnect.ke/v1/emails/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer tfm_k_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from_: {
      email: "hello@yourdomain.com",
      name: "Your Company",
    },
    to: [{ email: "customer@example.com", name: "Jane Doe" }],
    subject: "Your order has shipped",
    html: "<h1>Order Shipped</h1><p>Your package is on the way.</p>",
    text: "Order Shipped\n\nYour package is on the way.",
    tags: ["transactional", "order-updates"],
  }),
});
 
const data = await response.json();
console.log(data.id); // email ID

Example: Python (requests)

import requests
 
response = requests.post(
    "https://govconnect.ke/v1/emails/",
    headers={"Authorization": "Bearer tfm_k_YOUR_API_KEY"},
    json={
        "from_": {
            "email": "hello@yourdomain.com",
            "name": "Your Company",
        },
        "to": [{"email": "customer@example.com", "name": "Jane Doe"}],
        "subject": "Your order has shipped",
        "html": "<h1>Order Shipped</h1><p>Your package is on the way.</p>",
        "text": "Order Shipped\n\nYour package is on the way.",
        "tags": ["transactional", "order-updates"],
    },
)
 
data = response.json()
print(data["id"])

Response

A successful request returns 202 Accepted:

{
  "id": "3f8c1e2a-9b4d-4c7e-8a1f-2d6b5e9c0a3d",
  "status": "queued",
  "message_id": "<...@govconnect.ke>",
  "rejection_reason": null
}
FieldDescription
idThe email's UUID. Use this to query status, events, or retry.
statusqueued for an immediate send, scheduled if send_at was provided.
message_idRFC 5322 Message-ID header value.
rejection_reasonReason the email was rejected, or null if accepted.

A 202 means the email was accepted for delivery, not that it was delivered. Use webhooks or the events endpoint to track delivery status.

POST /v1/emails/validate

Dry-run validation. Checks whether an email would send without actually sending it. It validates the sender address, domain verification, plan send limits, recipients, content, and account restrictions. The request body is identical to POST /v1/emails/.

curl -X POST https://govconnect.ke/v1/emails/validate \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_": {"email": "hello@yourdomain.com"},
    "to": [{"email": "customer@example.com"}],
    "subject": "Test",
    "html": "<p>Hello</p>"
  }'

Response:

{
  "valid": true,
  "can_send": true,
  "issues": [],
  "plan": "starter",
  "usage": {
    "daily": 12,
    "daily_limit": 5000,
    "monthly": 340,
    "monthly_limit": 50000
  }
}

If a check fails, issues contains one or more {field, error} objects and both valid and can_send are false.

GET /v1/emails/:id

Retrieve a single email by its UUID, including its bodies, headers, and event history.

curl https://govconnect.ke/v1/emails/3f8c1e2a-9b4d-4c7e-8a1f-2d6b5e9c0a3d \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY"

GET /v1/emails/:id/events

List every tracked event for an email (queued, sent, delivered, opened, clicked, bounced, cancelled, and so on). Each event has an event_type, optional metadata, and a created_at timestamp.

curl https://govconnect.ke/v1/emails/3f8c1e2a-9b4d-4c7e-8a1f-2d6b5e9c0a3d/events \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY"

POST /v1/emails/:id/retry

Retry a previously failed email. Only emails with status bounced, rejected, or failed can be retried; any other status returns 409 Conflict. The retry creates a new email row linked back to the original; the original is preserved. The response shape matches POST /v1/emails/.

curl -X POST https://govconnect.ke/v1/emails/3f8c1e2a-9b4d-4c7e-8a1f-2d6b5e9c0a3d/retry \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY"

GET /v1/emails/search

Search emails by recipient, sender, subject, status, domain, or tag. The free-text q parameter accepts inline tokens that translate to structured filters:

TokenEffect
to:gmail.comSubstring match on the recipient list.
from:hello@govconnect.keSubstring match on the sender address.
status:bouncedExact status match.
domain:govconnect.keSubstring match on the sending domain.
tag:welcomeExact tag match.

Any remaining words become a free-text search across sender, subject, and recipients. Status and tag can also be passed as the separate query parameters status and tag. Results are paginated with page (default 0) and limit (default 20, max 100).

curl "https://govconnect.ke/v1/emails/search?q=status:bounced+to:gmail.com" \
  -H "Authorization: Bearer tfm_k_YOUR_API_KEY"

GET /v1/emails/

List emails with an optional status filter and page / limit pagination.

Error handling

StatusMeaning
400 Bad RequestInvalid attachment encoding, bad send_at value, or batch size over the plan limit.
401 UnauthorizedMissing or invalid API key.
403 ForbiddenPlan feature gate or send limit reached.
404 Not FoundThe referenced email does not exist.
409 ConflictThe email cannot be retried in its current status.
413 Payload Too LargeAttachment exceeds the per-file or combined size cap.
422 Unprocessable EntityValidation error in the request body.

On this page