# Email Setup Guide

> Add email as a channel on your sender profile with a domain you own

Email is configured as a **channel** on a sender profile, sending from a domain you own and verify. No identity verification is needed to send email: a verified domain and your plan's quota are all it takes.

## 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

![Sender profiles list](https://www.zavu.dev/docs/images/guides/email/sender-profiles-list.png)

---

## Sandbox email is no longer available

Sandbox domains (`*.sandbox.zavu.dev`) have been retired. Every email channel sends from a domain you own. A sender still configured with a sandbox domain must be reconfigured with a verified domain to keep sending; the steps below cover it.

---

## Custom Domain Email

Add your own domain to send from addresses like `noreply@yourcompany.com`.

  
#### Add your domain

    Domains are managed under **Accounts**, so one domain can serve several senders. Add your domain there (e.g., `yourcompany.com`). The Email channel dialog links to it with **Go to Accounts to add a domain** when the project has none yet.
  
  
#### Configure DKIM records

    Open the domain's **DNS panel**. It lists the DKIM CNAME records to add at your DNS provider, formatted for that provider. Copy each record and add it:

    ![DKIM records table](https://www.zavu.dev/docs/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.
  
  
#### Wait for verification

    Verification runs automatically in the background once the records propagate; you can close the dialog and Zavu notifies you when it is done. Once verified, the domain status changes to **Verified** and the from address fields appear.
  
  
#### Select the domain on your sender

    Go to **Sender Profiles** > your sender > **Channels** tab > click the **Email** card, and pick the domain under **Email Domain**.
  
  
#### 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`
  
  
#### Save

    Click **Save** to enable the email channel with your custom domain.
  

> **Note:**
> No identity verification is required to send email, single sends and broadcasts alike. What applies is your plan's email quota (100 a day and 3,000 a month on Free), the reputation of your domain, and the automated review every email passes through before it leaves. See [Sending limits](https://www.zavu.dev/docs/concepts/sending-limits).

### Send a Test Email

```typescript
import Zavu from "@zavudev/sdk";

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

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

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

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

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

### Create an email sender via the API

Once a domain is verified (dashboard or above), you can create an email sender programmatically — no phone number required. Set `emailAddress` to a from-address at your verified domain:

```bash
curl -X POST https://api.zavu.dev/v1/senders \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Transactional",
    "emailAddress": "noreply@yourdomain.com",
    "emailFromName": "Your Company",
    "setAsDefault": true
  }'
```

```typescript
const sender = await zavu.senders.create({
  name: "Transactional",
  emailAddress: "noreply@yourdomain.com",
  emailFromName: "Your Company",
  setAsDefault: true,
});
```

The address's domain must already be verified in your project. `emailDomainId` is optional — Zavu resolves it from the address. To attach an email address to an **existing** sender instead, `PATCH /v1/senders/{senderId}` with the same `emailAddress` field.

Then send from it — as the default sender, or by passing its ID in the `Zavu-Sender` header:

```bash
curl -X POST https://api.zavu.dev/v1/messages \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "user@example.com", "channel": "email", "subject": "Hi", "text": "Hello!" }'
```

> **Note:**
> Passing `from` in the send body does **not** create or select a sender — the from-address comes from the sender's configured `emailAddress`. Create the email sender first (above), then it sends as the default or via `Zavu-Sender`.

---

## Receiving Emails

Zavu can receive inbound emails and deliver them to your application via webhooks. Your domain needs an MX record for it.

### Add the MX record

  
#### Open the Email channel dialog

    Go to your sender > **Channels** > **Email** card.
  
  
#### 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
    ```
  
  
#### Verify MX record

    After adding the record, click **Verify MX**. Once verified, the toggle becomes available.
  
  
#### Enable receiving

    Toggle **Enable Email Receiving** on and save.
  

### 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:

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

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

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

```json
{
  "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](https://www.zavu.dev/docs/guides/receiving-messages/webhooks) for details on signature verification and security.

### Catch-all: receive every address at your domain

By default a sender only receives email sent to its exact address (e.g. `support@yourcompany.com`). Enable **Catch-all** to receive email addressed to **any** local part at the domain — `sales@`, `billing@`, `hello@`, or an address that doesn't exist as its own sender — all delivered through this one sender's webhook.

  
#### Enable receiving first

    Catch-all builds on receiving, so **Enable Email Receiving** must be on (the domain's MX record must be verified). See the steps above.
  
  
#### Toggle Catch-all

    In the sender's **Channels > Email** dialog, turn on **Catch-all address** and save. The toggle only appears once receiving is enabled.
  

Every catch-all message fires the same `message.inbound` event. Route sub-addresses yourself using `data.to`, which is always the **original recipient**:

```json
{
  "type": "message.inbound",
  "data": {
    "to": "sales@yourcompany.com",
    "from": "customer@gmail.com",
    "channel": "email",
    "subject": "Interested in a demo",
    "text": "..."
  }
}
```

You can also toggle catch-all from the API with `emailCatchAllEnabled` on the sender:

```bash
curl -X PATCH https://api.zavu.dev/v1/senders/sender_abc123 \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emailReceivingEnabled": true, "emailCatchAllEnabled": true }'
```

> **Note:**
> Catch-all is per sender. Only one sender per domain should have it enabled — it owns all otherwise-unmatched addresses for that domain. Addresses that exactly match another sender still route to that sender. `emailCatchAllEnabled` is ignored unless `emailReceivingEnabled` is also on.

---

## 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; verification runs automatically, and the **DNS panel** shows which records are still missing |
| `daily_limit_exceeded` error | The plan's daily email quota is spent (100 a day on Free) | Wait for 00:00 UTC or upgrade the plan |
| Emails going to spam | Missing SPF or DMARC records, or a new domain | Publish the recommended SPF and DMARC records (`GET /v1/email-domains/{domainId}` lists them) and ramp volume up gradually |
| Inbound not working | MX record missing or not verified | Add MX record and click **Verify MX** |
| Only the exact address receives mail | Catch-all not enabled | Turn on **Catch-all address** in the Email channel dialog |
| Can't toggle receiving | MX record not verified yet | Verify MX record first |

## Next Steps

- [Sending Emails](https://www.zavu.dev/docs/guides/sending-messages/email) - API reference for email messages
- [Webhooks](https://www.zavu.dev/docs/guides/receiving-messages/webhooks) - Set up webhooks for delivery events
- [Email Health](https://www.zavu.dev/docs/guides/email-health/overview) - Monitor bounce rates and deliverability
