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

# Sending events

> Subscribe to sending events. Receive real-time notifications when emails are delivered, bounced, opened, clicked, or encounter issues.

Nuntly emits webhook events throughout the sending lifecycle so your application can react in real time. You subscribe to these events through the same [webhook configuration](/docs/guides/webhooks) used for receiving events.

## Available events

| Event                   | Description                                                             |
| ----------------------- | ----------------------------------------------------------------------- |
| `email.sent`            | The email has been accepted for delivery                                |
| `email.delivered`       | The email was successfully delivered to the recipient's mail server     |
| `email.opened`          | The recipient opened the email (requires open tracking on your domain)  |
| `email.clicked`         | The recipient clicked a link in the email (requires click tracking)     |
| `email.bounced`         | The email was rejected by the recipient's server                        |
| `email.complained`      | The recipient marked the email as spam                                  |
| `email.rejected`        | Nuntly refused to send the email due to a policy or configuration issue |
| `email.deliveryDelayed` | Delivery to the recipient is temporarily delayed                        |
| `email.failed`          | The email could not be delivered                                        |

<Note>
  Open and click tracking events require tracking to be enabled on your [sending domain](/docs/guides/sending-domains#enable-open-and-click-tracking).
</Note>

## Event payloads

All sending events share a common envelope. The `type` field identifies the event, and the `data` field contains the event-specific payload along with the base email fields.

**Base email fields** (present on all sending events):

| Field        | Type              | Description                                    |
| ------------ | ----------------- | ---------------------------------------------- |
| `id`         | string            | Unique event identifier.                       |
| `messageId`  | string            | The email message identifier.                  |
| `domainName` | string            | The sending domain.                            |
| `from`       | string            | Sender address.                                |
| `to`         | string or array   | Recipient address(es).                         |
| `subject`    | string            | Email subject line.                            |
| `sentAt`     | string (ISO 8601) | When the email was submitted.                  |
| `tags`       | object            | Key-value tags attached to the email (if any). |

### email.sent

Emitted when an email is accepted for delivery.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.sent",
  "createdAt": "2025-01-15T10:30:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z"
  }
}
```

### email.delivered

Emitted when the email is successfully delivered to the recipient's mail server.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.delivered",
  "createdAt": "2025-01-15T10:30:05.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "delivery": {
      "deliveredAt": "2025-01-15T10:30:05.000Z",
      "recipients": ["recipient@example.com"],
      "smtpResponse": "250 2.0.0 OK",
      "remoteMtaIp": "74.125.130.27",
      "reportingMta": "dns; mail.yourdomain.com",
      "processingTime": 234
    }
  }
}
```

### email.opened

Emitted when the recipient opens the email. Requires open tracking to be enabled on your sending domain.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.opened",
  "createdAt": "2025-01-15T11:15:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "open": {
      "openedAt": "2025-01-15T11:15:00.000Z",
      "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15"
    }
  }
}
```

### email.clicked

Emitted when the recipient clicks a link in the email. Requires click tracking to be enabled on your sending domain.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.clicked",
  "createdAt": "2025-01-15T11:16:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "click": {
      "clickedAt": "2025-01-15T11:16:00.000Z",
      "link": "https://yourdomain.com/getting-started",
      "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15"
    }
  }
}
```

### email.bounced

Emitted when the email is rejected by the recipient's mail server. Hard bounces indicate a permanent failure (for example, the address does not exist). Soft bounces are transient.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.bounced",
  "createdAt": "2025-01-15T10:30:10.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "invalid@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "bounce": {
      "bounceType": "Permanent",
      "bounceSubType": "General",
      "bouncedAt": "2025-01-15T10:30:10.000Z",
      "feedbackId": "feedback_01kabn43yqyxn2bx4ve84mczd3",
      "reportingMta": "dns; mail.example.com",
      "bouncedRecipients": [
        {
          "email": "invalid@example.com",
          "action": "failed",
          "status": "5.1.1",
          "diagnosticCode": "smtp; 550 5.1.1 The email account does not exist"
        }
      ]
    }
  }
}
```

### email.complained

Emitted when the recipient marks the email as spam.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.complained",
  "createdAt": "2025-01-15T12:00:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "complaint": {
      "complainedAt": "2025-01-15T12:00:00.000Z",
      "feedbackId": "feedback_01kabn43yqyxn2bx4ve84mczd3",
      "complaintFeedbackType": "abuse",
      "complainedRecipients": [
        { "email": "recipient@example.com" }
      ]
    }
  }
}
```

### email.rejected

Emitted when Nuntly refuses to send the email due to a policy or configuration issue (for example, the recipient is on a suppression list).

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.rejected",
  "createdAt": "2025-01-15T10:30:01.000Z",
  "data": {
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "reject": {
      "reason": "Address is on the suppression list"
    }
  }
}
```

### email.deliveryDelayed

Emitted when delivery to the recipient is temporarily delayed. The email may still be delivered after retry attempts.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.deliveryDelayed",
  "createdAt": "2025-01-15T10:35:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "deliveryDelay": {
      "delayType": "RecipientServerError",
      "delayedAt": "2025-01-15T10:35:00.000Z",
      "deliveryStoppedAt": "2025-01-15T11:35:00.000Z",
      "reportingMta": "dns; mail.example.com",
      "delayedRecipients": [
        {
          "email": "recipient@example.com",
          "status": "4.4.1",
          "diagnosticCode": "smtp; 421 Try again later"
        }
      ]
    }
  }
}
```

### email.failed

Emitted when the email could not be delivered after all retry attempts.

```json theme={null}
{
  "id": "evt_01kabn43yqyxn2bx4ve84mczd3",
  "type": "email.failed",
  "createdAt": "2025-01-15T11:30:00.000Z",
  "data": {
    "id": "email_01kabn43yqyxn2bx4ve84mczd3",
    "messageId": "msg_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "from": "hello@yourdomain.com",
    "to": "recipient@example.com",
    "subject": "Welcome to Nuntly",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "enqueuedAt": "2025-01-15T10:29:59.000Z",
    "failure": {
      "error": "Rendering failed: template variable 'user.name' is undefined"
    }
  }
}
```

## Subscribe to sending events

Add sending events to your webhook configuration through the dashboard or the SDK.

```typescript theme={null}
import { Nuntly } from '@nuntly/sdk';

const nuntly = new Nuntly({
  apiKey: process.env.NUNTLY_API_KEY,
});

const webhook = await nuntly.webhooks.create({
  name: 'Sending listener',
  endpointUrl: 'https://yourapp.com/api/webhooks/sending',
  status: 'enabled',
  events: [
    'email.delivered',
    'email.bounced',
    'email.complained',
    'email.opened',
    'email.clicked',
  ],
});

console.log('Webhook ID:', webhook.id);
console.log('Signing secret:', webhook.signingSecret);
```

<Warning>
  The signing secret is displayed only once. Store it securely. You need it to verify incoming webhook requests.
</Warning>

## Handle sending events

Use the same signature verification flow described in [handle webhook events](/docs/guides/integrate-webhooks). Here is a condensed example handling sending events:

```typescript theme={null}
// Inside your webhook handler (after signature verification)
const event = JSON.parse(payload);

switch (event.type) {
  case 'email.delivered':
    console.log(`Delivered to ${event.data.to}`);
    break;
  case 'email.bounced':
    console.log(`Bounced (${event.data.bounce.bounceType}): ${event.data.bounce.bouncedRecipients[0].email}`);
    // Remove hard-bounced addresses from your mailing list
    break;
  case 'email.complained':
    console.log(`Complaint from ${event.data.to}`);
    // Unsubscribe the recipient
    break;
  case 'email.opened':
    console.log(`Opened at ${event.data.open.openedAt}`);
    break;
  case 'email.clicked':
    console.log(`Clicked link: ${event.data.click.link}`);
    break;
}
```

## Learn more

<CardGroup cols={2}>
  <Card title="Set up webhooks" icon="webhook" href="/docs/guides/webhooks">
    Create and configure webhook endpoints
  </Card>

  <Card title="Handle webhook events" icon="code" href="/docs/guides/integrate-webhooks">
    Implement signature verification and event handling
  </Card>

  <Card title="Receiving events" icon="inbox" href="/docs/guides/receiving-webhooks">
    Webhook payloads for the receiving pipeline
  </Card>

  <Card title="Sending domains" icon="globe" href="/docs/guides/sending-domains">
    Enable open and click tracking on your domain
  </Card>
</CardGroup>
