> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tawked.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Email quickstart

> Send your first e-mail with Tawked Email: verify your domain with three CNAME records, create a live key with email:send, send a message, read its status and add the webhook.

At the end of this page your domain has sent an e-mail through the API, and your server hears what happened to it.

<Prompt description="Ask your coding assistant to add Tawked Email to your project." actions={["copy", "cursor"]}>
  Add transactional e-mail to this project with Tawked Email (docs: [https://docs.tawked.com/email/quickstart](https://docs.tawked.com/email/quickstart)).

  * Read the key from the environment variable TAWKED\_KEY, on the server only. Never send it to a browser or a mobile app.
  * Send with POST [https://tawked.com/v1/email/messages](https://tawked.com/v1/email/messages): from (name and an address on our verified domain), to (one address), subject, html and text. Send an Idempotency-Key per business event and retry a 502 or a network error with the same key.
  * Store the returned id next to the order or event, and update the status from email.\* webhooks (verify the tawked-signature header) or GET /v1/email/messages/ID.
  * Handle 422 errors by their error field (sender\_not\_verified, invalid\_destination, recipient\_suppressed) without retrying them.
</Prompt>

**Before you start**

* A Tawked account with an application that has Email on. [Sign up](https://tawked.com/en/signup) if you have none.
* Early access to Tawked Email. It is **early access**: open the application's **Email** area in the console and apply with what you send, how much a month and your domain. Tawked's team reviews each request and tells you on WhatsApp, in the console and by e-mail. Until it is approved, you cannot add a domain, and a send answers `403 email_early_access`.
* A domain you own, and access to its DNS.

<Steps>
  <Step title="Verify your domain">
    Open the application, then **Email → Setup**, and add your domain, `acme.sa` for example. The console shows three CNAME records:

    | Type | Name | Value |
    | - | - | - |
    | CNAME | `<token1>._domainkey.acme.sa` | `<token1>.dkim.amazonses.com` |
    | CNAME | `<token2>._domainkey.acme.sa` | `<token2>.dkim.amazonses.com` |
    | CNAME | `<token3>._domainkey.acme.sa` | `<token3>.dkim.amazonses.com` |

    Add the three at your DNS provider exactly as shown. They sign every message with DKIM, which is what mail servers check. Tawked looks for them every ten minutes; press **Check now** to look at once. Most providers publish a record within minutes. A domain whose records are not found within 72 hours is marked failed, and you can add it again.

    Nothing else in your DNS changes: your MX records, your SPF record and your mailboxes stay as they are.

    <Tip>
      If your domain has no DMARC record yet, add one: a TXT record at `_dmarc.acme.sa` with `v=DMARC1; p=none; rua=mailto:dmarc@acme.sa` to start. Gmail and Yahoo expect DMARC from domains that send at volume, and DKIM from these records is what makes your mail pass it.
    </Tip>
  </Step>

  <Step title="Create a live key">
    On **Application settings → API keys**, press **Create a key**. Choose the type **Live**, and under **Access** either **All products** or **Custom** with Email set to **Send** (the `email:send` scope). Copy the key: it shows once. Put it in your server's environment as `TAWKED_KEY`.

    A test key does not work here: the e-mail endpoints answer it `403 live_key_required`. Send your first messages to your own address instead.
  </Step>

  <Step title="Send a message">
    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST https://tawked.com/v1/email/messages \
        -H "Authorization: Bearer $TAWKED_KEY" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: order-1042-confirmation" \
        -d '{
          "from": { "name": "متجر أكمي", "address": "orders@acme.sa" },
          "to": "you@example.com",
          "subject": "طلبك رقم 1042 قيد التجهيز",
          "html": "<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>",
          "text": "مرحبًا سارة، استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.",
          "reference": "order-1042"
        }'
      ```

      ```javascript Node.js theme={"dark"}
      const res = await fetch('https://tawked.com/v1/email/messages', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.TAWKED_KEY}`,
          'Content-Type': 'application/json',
          'Idempotency-Key': 'order-1042-confirmation',
        },
        body: JSON.stringify({
          from: { name: 'متجر أكمي', address: 'orders@acme.sa' },
          to: 'you@example.com',
          subject: 'طلبك رقم 1042 قيد التجهيز',
          html: '<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>',
          text: 'مرحبًا سارة، استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.',
          reference: 'order-1042',
        }),
      });
      const message = await res.json(); // keep message.id next to the order
      ```

      ```php PHP theme={"dark"}
      $res = Http::withToken(env('TAWKED_KEY'))
          ->withHeaders(['Idempotency-Key' => 'order-1042-confirmation'])
          ->post('https://tawked.com/v1/email/messages', [
              'from' => ['name' => 'متجر أكمي', 'address' => 'orders@acme.sa'],
              'to' => 'you@example.com',
              'subject' => 'طلبك رقم 1042 قيد التجهيز',
              'html' => '<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>',
              'text' => 'مرحبًا سارة، استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.',
              'reference' => 'order-1042',
          ]);
      $id = $res->json('id'); // keep the id next to the order
      ```

      ```python Python theme={"dark"}
      import os, requests

      res = requests.post(
          "https://tawked.com/v1/email/messages",
          headers={
              "Authorization": f"Bearer {os.environ['TAWKED_KEY']}",
              "Idempotency-Key": "order-1042-confirmation",
          },
          json={
              "from": {"name": "متجر أكمي", "address": "orders@acme.sa"},
              "to": "you@example.com",
              "subject": "طلبك رقم 1042 قيد التجهيز",
              "html": "<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>",
              "text": "مرحبًا سارة، استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.",
              "reference": "order-1042",
          },
      )
      message_id = res.json()["id"]  # keep the id next to the order
      ```
    </CodeGroup>

    The answer is `202 Accepted`: the message is recorded and on its way.

    ```json theme={"dark"}
    {
      "id": "3d9a7f2e-1c4b-4e8a-9f6d-2b5c8e1a7d40",
      "status": "accepted",
      "from": { "name": "متجر أكمي", "address": "orders@acme.sa" },
      "to": "you@example.com",
      "subject": "طلبك رقم 1042 قيد التجهيز",
      "reference": "order-1042",
      "price_halalas": 1,
      "created_at": "2026-10-09T12:00:00+03:00"
    }
    ```

    The likely refusals: `403 insufficient_scope` (the key's access does not include Email send), `403 email_early_access` (the account has not been granted early access yet), `409 no_verified_domain` (no domain of this application is verified yet), `422 sender_not_verified` (the `from` address is on another domain). [Sending email](/email/messages#errors) lists every code.
  </Step>

  <Step title="Read the status">
    ```bash theme={"dark"}
    curl https://tawked.com/v1/email/messages/3d9a7f2e-1c4b-4e8a-9f6d-2b5c8e1a7d40 \
      -H "Authorization: Bearer $TAWKED_KEY"
    ```

    `status` moves from `accepted` to `sent` and `delivered` as the receiving mailbox answers, or ends as `bounced` or `failed` with `error` set. The message is on **Email → Messages** too.
  </Step>

  <Step title="Add the webhook">
    On **Application settings → Webhooks**, set your endpoint's URL. Every event of the application reaches it, so Tawked then posts `email.delivered`, `email.bounced`, `email.complained` and `email.failed` as they happen, signed like every other event. See [Webhooks](/webhooks) for the signature and [Sending email](/email/messages#webhooks) for the payload.
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.