Sending emails

Transactional emails

Send password resets, receipts and notifications from your app

A transactional email is sent by your app to one person, because of something they just did: a password reset, a sign-in link, a receipt, an invitation. It needs no list and has no unsubscribe link. It travels on its own stream, so it keeps flowing when marketing is paused.

Two ways to send

TemplateRaw content
Content lives inKula: anyone on the team edits it in the dashboardYour code
You sendThe template alias and variablesThe subject and the HTML or Markdown
Best forMost emailsEmails your app already renders

Create a template

Open Transactional › New template:

  • a Name, internal;
  • an Alias, the key your code sends as template, such as password-reset;
  • the Subject, Preview text, sender and content, written in the editor.

Use data.* variables for the values your app sends: {{ data.reset_url }}, {{ data.order.total }}. In Sample data, type example values as JSON to fill the preview and test emails:

{
  "name": "Ada",
  "reset_url": "https://acme.com/reset?token=abc123"
}

If the recipient is also a contact of your space, {{ contact.first_name }} and the contact's attributes work too.

Draft and published versions

A template has a draft and a published version. The API always sends the published version: editing the draft does not change emails in production.

StatusMeaning
DraftNever published: the API refuses to send it
PublishedThe draft and the published version are the same
Unpublished changesYou edited the draft since the last publication

Preview and Send a test use the draft. Click Publish to make the draft live, or Discard draft to go back to the published version.

AI assistants can write a template draft but never publish it: they ask a member, who clicks Approve and publish.

Send it from your app

Create an API key in Settings › API keys. A key with sending access is enough, and safer to store in an app. Then call POST /v1/emails:

cURL
curl https://api.kulamail.com/v1/emails \
  -H "Authorization: Bearer $KULA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reset-8f6c2a1e" \
  -d '{
    "to": "ada@example.com",
    "template": "password-reset",
    "variables": {
      "name": "Ada",
      "reset_url": "https://acme.com/reset?token=abc123"
    }
  }'

The email is queued and leaves within seconds. The template page shows the same snippet, in cURL and Node, with your alias and sample data.

  • Sender: the sender of the template, or the default sender of the space. Override it with from, on a verified domain.
  • Idempotency: send an Idempotency-Key header. If your app retries after a timeout, Kula returns the first email instead of sending a second one.
  • Batches: send up to 100 emails in one call with POST /v1/emails/batch.
  • Tags: attach key/value tags to find the email in webhooks.

Every field and error: Emails API.

A separate stream

MarketingTransactional
Priority in the queueNormalFirst
Paused on a reputation alertYesNo
Warm-up of a new domainAppliesSkipped
Contact reviewAppliesSkipped
Unsubscribed contactsSkippedStill receive it
Hard-bounced addressesSkippedSkipped

A hard-bounced address is blocked on both streams: the email comes back with the status SUPPRESSED and is not sent.

Use transactional emails only for messages a person expects after an action. Newsletters and promotions sent through the transactional API skip the unsubscribe rules of inbox providers and break our acceptable use policy.

Follow what happens

  • Activity lists every email, with its status and events. Filter on the transactional stream.
  • Each template page shows its sends, deliveries, opens and clicks over 30 days.
  • Webhooks tell your app when an email is delivered, bounces, is opened or clicked.

Raw content you send (HTML or Markdown, without a template) is kept 30 days, then deleted.

Emails API

Fields, batches and errors

Templates API

Manage templates from your code

Webhooks

Delivery, bounce, open and click events