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

# Sending Emails

> Send transactional emails to any email address

Email is ideal for rich content delivery, transactional notifications, and messages that need to be referenced later.

## When to Use Email

* **Transactional emails**: Order confirmations, receipts, shipping updates
* **Account notifications**: Password resets, security alerts, welcome emails
* **Rich content**: HTML formatting, images, detailed information
* **File attachments**: Invoices, receipts, reports, documents (up to 40MB)
* **Asynchronous communication**: Messages that don't require immediate attention

<Note>
  Email operates as a separate channel and does not participate in smart routing. You must explicitly specify `channel: "email"` or send to an email address.
</Note>

## Sending an Email

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.send({
    to: "user@example.com",
    channel: "email",
    subject: "Your order has shipped",
    text: "Hi John, your order #12345 has shipped and will arrive in 2-3 business days."
  });
  ```

  ```python Python theme={null}
  result = zavu.messages.send(
      to="user@example.com",
      channel="email",
      subject="Your order has shipped",
      text="Hi John, your order #12345 has shipped and will arrive in 2-3 business days."
  )
  ```

  ```ruby Ruby theme={null}
  result = client.messages.send(
    to: "user@example.com",
    channel: "email",
    subject: "Your order has shipped",
    text: "Hi John, your order #12345 has shipped and will arrive in 2-3 business days."
  )
  ```

  ```go Go theme={null}
  result, _ := client.Messages.Send(context.TODO(), zavudev.MessageSendParams{
  	To:      zavudev.String("user@example.com"),
  	Channel: zavudev.String("email"),
  	Subject: zavudev.String("Your order has shipped"),
  	Text:    zavudev.String("Hi John, your order #12345 has shipped and will arrive in 2-3 business days."),
  })
  ```

  ```php PHP theme={null}
  <?php
  $result = $client->messages->send([
      'to' => 'user@example.com',
      'channel' => 'email',
      'subject' => 'Your order has shipped',
      'text' => 'Hi John, your order #12345 has shipped and will arrive in 2-3 business days.',
  ]);
  ```

  ```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": "user@example.com",
      "channel": "email",
      "subject": "Your order has shipped",
      "text": "Hi John, your order #12345 has shipped and will arrive in 2-3 business days."
    }'
  ```
</CodeGroup>

<Tip>
  You can optionally specify a sender by passing `zavuSender` (TypeScript), `zavu_sender` (Python), or the `Zavu-Sender` header (cURL). If omitted, your project's default sender is used.
</Tip>

## HTML Emails

Send rich HTML emails by including `htmlBody`. The `text` field serves as the plain-text fallback:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.send({
    to: "user@example.com",
    channel: "email",
    subject: "Welcome to Zavu",
    text: "Welcome to Zavu! We are excited to have you on board.",
    htmlBody: `
      <h1>Welcome to Zavu!</h1>
      <p>We are excited to have you on board.</p>
      <a href="https://dashboard.zavu.dev">Get Started</a>
    `,
    replyTo: "support@yourcompany.com"
  });
  ```

  ```python Python theme={null}
  result = zavu.messages.send(
      to="user@example.com",
      channel="email",
      subject="Welcome to Zavu",
      text="Welcome to Zavu! We are excited to have you on board.",
      html_body="""
          <h1>Welcome to Zavu!</h1>
          <p>We are excited to have you on board.</p>
          <a href="https://dashboard.zavu.dev">Get Started</a>
      """,
      reply_to="support@yourcompany.com"
  )
  ```

  ```ruby Ruby theme={null}
  result = client.messages.send(
    to: "user@example.com",
    channel: "email",
    subject: "Welcome to Zavu",
    text: "Welcome to Zavu! We are excited to have you on board.",
    html_body: "<h1>Welcome to Zavu!</h1><p>We are excited to have you on board.</p>",
    reply_to: "support@yourcompany.com"
  )
  ```

  ```go Go theme={null}
  result, _ := client.Messages.Send(context.TODO(), zavudev.MessageSendParams{
  	To:       zavudev.String("user@example.com"),
  	Channel:  zavudev.String("email"),
  	Subject:  zavudev.String("Welcome to Zavu"),
  	Text:     zavudev.String("Welcome to Zavu! We are excited to have you on board."),
  	HTMLBody: zavudev.String("<h1>Welcome to Zavu!</h1><p>We are excited to have you on board.</p>"),
  	ReplyTo:  zavudev.String("support@yourcompany.com"),
  })
  ```

  ```php PHP theme={null}
  <?php
  $result = $client->messages->send([
      'to' => 'user@example.com',
      'channel' => 'email',
      'subject' => 'Welcome to Zavu',
      'text' => 'Welcome to Zavu! We are excited to have you on board.',
      'htmlBody' => '<h1>Welcome to Zavu!</h1><p>We are excited to have you on board.</p>',
      'replyTo' => 'support@yourcompany.com',
  ]);
  ```

  ```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": "user@example.com",
      "channel": "email",
      "subject": "Welcome to Zavu",
      "text": "Welcome to Zavu! We are excited to have you on board.",
      "htmlBody": "<h1>Welcome to Zavu!</h1><p>We are excited to have you on board.</p>",
      "replyTo": "support@yourcompany.com"
    }'
  ```
</CodeGroup>

## Attachments

Send files by including the `attachments` array. Each attachment can provide file content as base64 or a URL to fetch from.

### Base64 Content

<CodeGroup>
  ```typescript TypeScript theme={null}
  const fs = require("fs");
  const content = fs.readFileSync("invoice.pdf").toString("base64");

  const result = await zavu.messages.send({
    to: "user@example.com",
    channel: "email",
    subject: "Your invoice",
    text: "Please find your invoice attached.",
    attachments: [
      {
        filename: "invoice.pdf",
        content: content,
        content_type: "application/pdf",
      },
    ],
  });
  ```

  ```python Python theme={null}
  import base64

  with open("invoice.pdf", "rb") as f:
      content = base64.b64encode(f.read()).decode()

  result = zavu.messages.send(
      to="user@example.com",
      channel="email",
      subject="Your invoice",
      text="Please find your invoice attached.",
      attachments=[
          {
              "filename": "invoice.pdf",
              "content": content,
              "content_type": "application/pdf",
          }
      ],
  )
  ```

  ```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": "user@example.com",
      "channel": "email",
      "subject": "Your invoice",
      "text": "Please find your invoice attached.",
      "attachments": [
        {
          "filename": "invoice.pdf",
          "content": "JVBERi0xLjQK...",
          "content_type": "application/pdf"
        }
      ]
    }'
  ```
</CodeGroup>

### URL Path

Instead of encoding the file, provide a URL and Zavu will fetch it:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.send({
    to: "user@example.com",
    channel: "email",
    subject: "Your report",
    text: "Please find your report attached.",
    attachments: [
      {
        filename: "report.pdf",
        path: "https://your-server.com/reports/report.pdf",
      },
    ],
  });
  ```

  ```python Python theme={null}
  result = zavu.messages.send(
      to="user@example.com",
      channel="email",
      subject="Your report",
      text="Please find your report attached.",
      attachments=[
          {
              "filename": "report.pdf",
              "path": "https://your-server.com/reports/report.pdf",
          }
      ],
  )
  ```

  ```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": "user@example.com",
      "channel": "email",
      "subject": "Your report",
      "text": "Please find your report attached.",
      "attachments": [
        {
          "filename": "report.pdf",
          "path": "https://your-server.com/reports/report.pdf"
        }
      ]
    }'
  ```
</CodeGroup>

### Inline Images

Embed images directly in HTML using `content_id`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.send({
    to: "user@example.com",
    channel: "email",
    subject: "Your weekly report",
    text: "See your weekly report.",
    htmlBody: `
      <h1>Weekly Report</h1>
      <img src="cid:chart" alt="Performance chart" />
      <p>Your performance improved 15% this week.</p>
    `,
    attachments: [
      {
        filename: "chart.png",
        path: "https://your-server.com/charts/weekly.png",
        content_type: "image/png",
        content_id: "chart",
      },
    ],
  });
  ```

  ```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": "user@example.com",
      "channel": "email",
      "subject": "Your weekly report",
      "text": "See your weekly report.",
      "htmlBody": "<h1>Weekly Report</h1><img src=\"cid:chart\" /><p>Improved 15%.</p>",
      "attachments": [
        {
          "filename": "chart.png",
          "path": "https://your-server.com/charts/weekly.png",
          "content_type": "image/png",
          "content_id": "chart"
        }
      ]
    }'
  ```
</CodeGroup>

### Attachment Fields

| Field          | Required | Description                                              |
| -------------- | -------- | -------------------------------------------------------- |
| `filename`     | Yes      | Name of the file                                         |
| `content`      | One of   | Base64-encoded file content                              |
| `path`         | One of   | URL to fetch the file from                               |
| `content_type` | No       | MIME type (auto-detected from filename if omitted)       |
| `content_id`   | No       | ID for inline images, reference in HTML as `cid:your_id` |

<Note>
  Each attachment must have either `content` or `path`, not both. Total attachment size is limited to **40MB** per email, and a maximum of **50 attachments** per message.
</Note>

## Request Fields

| Field         | Required | Description                            |
| ------------- | -------- | -------------------------------------- |
| `to`          | Yes      | Valid email address                    |
| `channel`     | Yes      | Must be `"email"`                      |
| `subject`     | Yes      | Email subject line (max 998 chars)     |
| `text`        | Yes      | Plain text body                        |
| `htmlBody`    | No       | HTML version of the email              |
| `replyTo`     | No       | Reply-To email address                 |
| `attachments` | No       | Array of file attachments (email only) |

## Channel Detection

If you send to an email address without specifying a channel, Zavu automatically selects email:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.send({
    to: "user@example.com",
    subject: "Hello",
    text: "This will be sent as email automatically"
  });
  ```

  ```python Python theme={null}
  result = zavu.messages.send(
      to="user@example.com",
      subject="Hello",
      text="This will be sent as email automatically"
  )
  ```

  ```ruby Ruby theme={null}
  result = client.messages.send(
    to: "user@example.com",
    subject: "Hello",
    text: "This will be sent as email automatically"
  )
  ```

  ```go Go theme={null}
  result, _ := client.Messages.Send(context.TODO(), zavudev.MessageSendParams{
  	To:      zavudev.String("user@example.com"),
  	Subject: zavudev.String("Hello"),
  	Text:    zavudev.String("This will be sent as email automatically"),
  })
  ```

  ```php PHP theme={null}
  <?php
  $result = $client->messages->send([
      'to' => 'user@example.com',
      'subject' => 'Hello',
      'text' => 'This will be sent as email automatically',
  ]);
  ```

  ```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": "user@example.com",
      "subject": "Hello",
      "text": "This will be sent as email automatically"
    }'
  ```
</CodeGroup>

## Setting Up Email

Before sending emails, you need to configure your sender with a verified domain.

### 1. Add Your Domain

Go to **Email Domains** in the dashboard and add your domain (e.g., `yourcompany.com`).

### 2. Configure DNS

Add the DKIM records provided by Zavu to your DNS:

```
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 48 hours in some cases.
</Tip>

### 3. Verify Domain

Zavu automatically checks your DNS records every 5 minutes. Once verified, your domain status will change to `verified`.

### 4. Assign to Sender

Assign the verified domain to a sender and configure your from address:

* **From address**: `noreply@yourcompany.com`
* **Reply-To address**: `support@yourcompany.com` (optional)

## Delivery Status

Check message status by ID:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await zavu.messages.get({ messageId: "msg_abc123" });
  console.log("Status:", result.message.status);
  ```

  ```python Python theme={null}
  result = zavu.messages.get(message_id="msg_abc123")
  print(f"Status: {result.message.status}")
  ```

  ```ruby Ruby theme={null}
  result = client.messages.get(message_id: "msg_abc123")
  puts "Status: #{result.message.status}"
  ```

  ```go Go theme={null}
  result, _ := client.Messages.Get(context.TODO(), "msg_abc123")
  fmt.Println("Status:", result.Message.Status)
  ```

  ```php PHP theme={null}
  <?php
  $result = $client->messages->get('msg_abc123');
  echo "Status: " . $result->message->status;
  ```

  ```bash cURL theme={null}
  curl https://api.zavu.dev/v1/messages/msg_abc123 \
    -H "Authorization: Bearer $ZAVU_API_KEY"
  ```
</CodeGroup>

| Status      | Description                |
| ----------- | -------------------------- |
| `queued`    | Accepted, pending delivery |
| `sending`   | Being sent to recipient    |
| `delivered` | Confirmed delivered        |
| `failed`    | Delivery failed            |

## Common Errors

| Error                   | Description              | Solution                                   |
| ----------------------- | ------------------------ | ------------------------------------------ |
| `subject_required`      | Missing subject line     | Include `subject` field                    |
| `sender_not_configured` | Sender lacks email setup | Configure email domain on sender           |
| `domain_not_verified`   | Domain not verified      | Complete DNS verification                  |
| `bounce`                | Email bounced            | Invalid or non-existent email address      |
| `complaint`             | Marked as spam           | Review email content and sending practices |

## Email vs SMS/WhatsApp

| Feature                | Email                 | SMS / WhatsApp          |
| ---------------------- | --------------------- | ----------------------- |
| **Smart Routing**      | No - explicit channel | Yes - auto-selected     |
| **Automatic Fallback** | No                    | Yes                     |
| **Recipient Type**     | Email address         | Phone number (E.164)    |
| **Rich Content**       | Full HTML support     | Limited (WhatsApp only) |
| **File Attachments**   | Yes (up to 40MB)      | Media only (WhatsApp)   |
| **Delivery Speed**     | Minutes               | Seconds                 |

<Warning>
  Email is a separate channel and does not fall back to SMS/WhatsApp if delivery fails.
</Warning>

## Best Practices

1. **Always include plain text** - Some email clients only show plain text
2. **Use a verified domain** - Improves deliverability and avoids spam filters
3. **Set Reply-To** - Make it easy for recipients to respond
4. **Keep subjects clear** - Descriptive subjects improve open rates
5. **Test before sending** - Preview HTML emails in multiple clients
6. **Respect unsubscribes** - Honor opt-out requests promptly

## Compliance

<Warning>
  Email messaging is regulated. Ensure you comply with CAN-SPAM, GDPR, and other applicable laws.
</Warning>

### Requirements

* **Consent**: Have permission before sending marketing emails
* **Unsubscribe**: Include a working unsubscribe link
* **Sender identification**: Clearly identify your business
* **Physical address**: Include your business address (for marketing emails)
* **Honest subject lines**: Don't use deceptive subject lines

### Example Compliant Email

```html theme={null}
<h1>Your Order Has Shipped!</h1>
<p>Hi John, your order #12345 has shipped.</p>
<p>Track your package: <a href="https://track.co/abc">View Tracking</a></p>

<hr>
<p style="font-size: 12px; color: #666;">
  YourCompany, Inc. | 123 Main St, San Francisco, CA 94102<br>
  <a href="https://yourcompany.com/unsubscribe">Unsubscribe</a>
</p>
```
