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

# Email Setup Guide

> Add email as a channel on your sender profile using sandbox or custom domains

Email is configured as a **channel** on a sender profile. You can start testing immediately with a sandbox domain, or add your own custom domain for production.

## Prerequisites

Before setting up email, you need a **sender profile**. If you don't have one yet:

1. Go to **Sender Profiles** in the dashboard
2. Click **New Sender** and give it a name
3. Once created, click on the sender to open its settings

<img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/sender-profiles-list.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=dc5bc9f8ed67fb1d3e3bfa231d3b234d" alt="Sender profiles list" width="1723" height="1114" data-path="images/guides/email/sender-profiles-list.png" />

***

## Sandbox Email (Quick Start)

Sandbox domains let you test email sending immediately without configuring DNS records.

<Note>
  Sandbox emails are limited to 100 emails/hour. No KYC required. Use a custom domain for production.
</Note>

<Steps>
  <Step title="Open your sender profile">
    Go to **Sender Profiles** and click on the sender you want to configure.
  </Step>

  <Step title="Go to the Channels tab">
    Click the **Channels** tab in the sender detail page.

    <img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/sender-channels-tab.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=8109bb8c8b1e6de900dd151ae2195264" alt="Sender channels tab" width="1481" height="1041" data-path="images/guides/email/sender-channels-tab.png" />
  </Step>

  <Step title="Add Email channel and activate Sandbox">
    Click the **Email** channel card to open the email configuration dialog. The dialog opens on the **Sandbox (Free)** tab by default. Click **Activate Sandbox Email** to create your sandbox domain.

    <img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/email-channel-card.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=35efdc3ae04c8a0902f0c1b7fe550bea" alt="Email channel card" width="675" height="671" data-path="images/guides/email/email-channel-card.png" />
  </Step>

  <Step title="Configure your from address">
    Once the sandbox domain is created, configure:

    * **From Email Address**: The local part before `@` (e.g., `noreply`)
    * **From Name**: The display name recipients see (e.g., `Your Company`)
    * **Reply-To Email** (optional): Where replies go
    * **Enable Email Receiving**: Toggle this on if you want to receive inbound emails on this address
  </Step>

  <Step title="Save">
    Click **Save** to enable the email channel on your sender.
  </Step>
</Steps>

### Send a Test Email

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Zavu from "@zavudev/sdk";

  const zavu = new Zavu({ apiKey: process.env.ZAVU_API_KEY });

  const result = await zavu.messages.send({
    to: "recipient@example.com",
    channel: "email",
    subject: "Test from Zavu Sandbox",
    text: "If you see this, your sandbox email is working!",
  });

  console.log("Message ID:", result.message.id);
  console.log("Status:", result.message.status);
  ```

  ```python Python theme={null}
  from zavudev import Zavu

  zavu = Zavu(api_key="your-api-key")

  result = zavu.messages.send(
      to="recipient@example.com",
      channel="email",
      subject="Test from Zavu Sandbox",
      text="If you see this, your sandbox email is working!",
  )

  print(f"Message ID: {result.message.id}")
  print(f"Status: {result.message.status}")
  ```

  ```ruby Ruby theme={null}
  require "zavudev"

  client = Zavudev::Client.new(api_key: ENV["ZAVUDEV_API_KEY"])

  result = client.messages.send(
    to: "recipient@example.com",
    channel: "email",
    subject: "Test from Zavu Sandbox",
    text: "If you see this, your sandbox email is working!"
  )

  puts "Message ID: #{result.message.id}"
  puts "Status: #{result.message.status}"
  ```

  ```go Go theme={null}
  result, _ := client.Messages.Send(context.TODO(), zavudev.MessageSendParams{
  	To:      zavudev.String("recipient@example.com"),
  	Channel: zavudev.String("email"),
  	Subject: zavudev.String("Test from Zavu Sandbox"),
  	Text:    zavudev.String("If you see this, your sandbox email is working!"),
  })

  fmt.Println("Message ID:", result.Message.ID)
  fmt.Println("Status:", result.Message.Status)
  ```

  ```php PHP theme={null}
  <?php
  $result = $client->messages->send([
      'to' => 'recipient@example.com',
      'channel' => 'email',
      'subject' => 'Test from Zavu Sandbox',
      'text' => 'If you see this, your sandbox email is working!',
  ]);

  echo "Message ID: " . $result->message->id . "\n";
  echo "Status: " . $result->message->status . "\n";
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.zavu.dev/v1/messages \
    -H "Authorization: Bearer $ZAVU_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "to": "recipient@example.com",
      "channel": "email",
      "subject": "Test from Zavu Sandbox",
      "text": "If you see this, your sandbox email is working!"
    }'
  ```
</CodeGroup>

<Tip>
  If you have multiple senders, use the `Zavu-Sender` header to specify which sender to use. Otherwise, the default sender is used.
</Tip>

### Sandbox vs Custom Domain

| Feature               | Sandbox                          | Custom Domain                   |
| --------------------- | -------------------------------- | ------------------------------- |
| **Rate limit**        | 100 emails/hour                  | Based on your plan              |
| **From address**      | `*@yourproject.sandbox.zavu.dev` | `*@yourdomain.com`              |
| **Deliverability**    | Lower (sandbox reputation)       | Higher (your domain reputation) |
| **Inbound receiving** | Supported                        | Supported (requires MX record)  |
| **KYC required**      | No                               | Yes                             |

***

## Custom Domain Email

For production use, add your own domain to send from addresses like `noreply@yourcompany.com`.

<Steps>
  <Step title="Open the Email channel dialog">
    Go to **Sender Profiles** > your sender > **Channels** tab > click the **Email** card.
  </Step>

  <Step title="Switch to Custom Domain tab">
    Click the **Custom Domain** tab at the top of the dialog.

    <img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/custom-domain-tab.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=232f7d49858c2ce8b181769d1789261e" alt="Custom domain tab" width="1474" height="1040" data-path="images/guides/email/custom-domain-tab.png" />
  </Step>

  <Step title="Add your domain">
    Select **Add new domain** from the dropdown and enter your domain (e.g., `yourcompany.com`).

    <img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/add-domain.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=79e6670b39711533d999e060925bda1b" alt="Add domain" width="1467" height="1042" data-path="images/guides/email/add-domain.png" />
  </Step>

  <Step title="Configure DKIM records">
    Zavu displays the DKIM CNAME records you need to add to your DNS. Copy each record and add them to your DNS provider:

    <img src="https://mintcdn.com/crubingllc/aSUs3--vtRO0jg_p/images/guides/email/dkim-records-table.png?fit=max&auto=format&n=aSUs3--vtRO0jg_p&q=85&s=4252477f754abe1bb2e70e14f5365456" alt="DKIM records table" width="1474" height="1034" data-path="images/guides/email/dkim-records-table.png" />

    The records look like:

    ```
    selector1._domainkey.yourcompany.com  CNAME  selector1.dkim.zavu.dev
    selector2._domainkey.yourcompany.com  CNAME  selector2.dkim.zavu.dev
    selector3._domainkey.yourcompany.com  CNAME  selector3.dkim.zavu.dev
    ```

    <Tip>
      DNS propagation typically takes a few minutes, but can take up to 72 hours. Use the copy buttons next to each record to avoid typos.
    </Tip>
  </Step>

  <Step title="Verify DNS">
    Click **Verify DNS** to check if your records have propagated. Once verified, the domain status changes to **Verified** and the from address fields appear.
  </Step>

  <Step title="Configure from address">
    Set your:

    * **From Email Address**: e.g., `noreply`
    * **From Name**: e.g., `Your Company`
    * **Reply-To Email** (optional): e.g., `support@yourcompany.com`
  </Step>

  <Step title="Save">
    Click **Save** to enable the email channel with your custom domain.
  </Step>
</Steps>

<Warning>
  Email sending with custom domains requires KYC verification. Complete identity verification in the dashboard before sending production emails.
</Warning>

***

## Receiving Emails

Zavu can receive inbound emails and deliver them to your application via webhooks. This works for both sandbox and custom domains.

### For Custom Domains: Add MX Record

<Steps>
  <Step title="Open the Email channel dialog">
    Go to your sender > **Channels** > **Email** card.
  </Step>

  <Step title="Find the MX record section">
    Under **Enable Email Receiving**, Zavu shows the MX record to add to your DNS:

    ```
    yourcompany.com  MX  10  inbound.zavu.dev
    ```
  </Step>

  <Step title="Verify MX record">
    After adding the record, click **Verify MX**. Once verified, the toggle becomes available.
  </Step>

  <Step title="Enable receiving">
    Toggle **Enable Email Receiving** on and save.
  </Step>
</Steps>

### For Sandbox Domains

Toggle **Enable Email Receiving** directly in the sandbox email configuration and save. No MX record needed.

### Set Up Webhook for Inbound Emails

To receive inbound emails in your application, configure a webhook on your sender:

1. Go to your sender > **Webhooks** tab
2. Add your webhook URL and subscribe to the `message.inbound` event

Or via the API:

<CodeGroup>
  ```typescript TypeScript theme={null}
  await zavu.senders.update({
    senderId: "sender_abc123",
    webhookUrl: "https://api.yourcompany.com/webhooks/zavu",
    webhookEvents: ["message.inbound"],
  });
  ```

  ```python Python theme={null}
  zavu.senders.update(
      sender_id="sender_abc123",
      webhook_url="https://api.yourcompany.com/webhooks/zavu",
      webhook_events=["message.inbound"],
  )
  ```

  ```ruby Ruby theme={null}
  client.senders.update(
    sender_id: "sender_abc123",
    webhook_url: "https://api.yourcompany.com/webhooks/zavu",
    webhook_events: ["message.inbound"]
  )
  ```

  ```go Go theme={null}
  client.Senders.Update(context.TODO(), "sender_abc123", zavudev.SenderUpdateParams{
  	WebhookURL:    zavudev.String("https://api.yourcompany.com/webhooks/zavu"),
  	WebhookEvents: []string{"message.inbound"},
  })
  ```

  ```php PHP theme={null}
  <?php
  $client->senders->update('sender_abc123', [
      'webhookUrl' => 'https://api.yourcompany.com/webhooks/zavu',
      'webhookEvents' => ['message.inbound'],
  ]);
  ```

  ```bash cURL theme={null}
  curl -X PATCH https://api.zavu.dev/v1/senders/sender_abc123 \
    -H "Authorization: Bearer $ZAVU_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "webhookUrl": "https://api.yourcompany.com/webhooks/zavu",
      "webhookEvents": ["message.inbound"]
    }'
  ```
</CodeGroup>

When an email is received, Zavu sends a `message.inbound` event:

```json theme={null}
{
  "id": "evt_1736850000000_abc123",
  "type": "message.inbound",
  "timestamp": 1736850000000,
  "senderId": "sender_abc123",
  "projectId": "proj_xyz789",
  "data": {
    "messageId": "msg_def456",
    "to": "support@yourcompany.com",
    "from": "customer@gmail.com",
    "channel": "email",
    "status": "received",
    "subject": "Question about my order",
    "text": "Hi, I have a question about order #12345..."
  }
}
```

<Tip>
  See the [Webhooks guide](/guides/receiving-messages/webhooks) for details on signature verification and security.
</Tip>

***

## Testing Your Setup

### Verify Sending

1. Send a test email using the code examples above
2. Check the message status in **Messages** in the dashboard
3. Verify the email arrived in the recipient's inbox

### Verify Receiving

1. Send an email to your configured address (e.g., `support@yourcompany.com`)
2. Check your webhook endpoint received the `message.inbound` event
3. Verify the inbound message appears in the dashboard under **Messages**

### Common Issues

| Issue                      | Cause                                  | Solution                                    |
| -------------------------- | -------------------------------------- | ------------------------------------------- |
| Email not delivered        | Sender has no email channel configured | Add email channel on your sender profile    |
| Domain stuck on "Pending"  | DNS records not propagated             | Wait up to 72 hours, click **Verify DNS**   |
| `email_kyc_required` error | KYC not completed                      | Complete identity verification in dashboard |
| Emails going to spam       | Using sandbox domain                   | Switch to a custom domain for production    |
| Inbound not working        | MX record missing or not verified      | Add MX record and click **Verify MX**       |
| Can't toggle receiving     | MX record not verified yet             | Verify MX record first                      |

## Next Steps

* [Sending Emails](/guides/sending-messages/email) - API reference for email messages
* [Webhooks](/guides/receiving-messages/webhooks) - Set up webhooks for delivery events
* [Email Health](/guides/email-health/overview) - Monitor bounce rates and deliverability
