Skip to main content
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 used for receiving events.

Available events

EventDescription
email.sentThe email has been accepted for delivery
email.deliveredThe email was successfully delivered to the recipient’s mail server
email.openedThe recipient opened the email (requires open tracking on your domain)
email.clickedThe recipient clicked a link in the email (requires click tracking)
email.bouncedThe email was rejected by the recipient’s server
email.complainedThe recipient marked the email as spam
email.rejectedNuntly refused to send the email due to a policy or configuration issue
email.deliveryDelayedDelivery to the recipient is temporarily delayed
email.failedThe email could not be delivered
Open and click tracking events require tracking to be enabled on your sending domain.

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):
FieldTypeDescription
idstringUnique event identifier.
messageIdstringThe email message identifier.
domainNamestringThe sending domain.
fromstringSender address.
tostring or arrayRecipient address(es).
subjectstringEmail subject line.
sentAtstring (ISO 8601)When the email was submitted.
tagsobjectKey-value tags attached to the email (if any).

email.sent

Emitted when an email is accepted for delivery.
{
  "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.
{
  "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.
{
  "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.
{
  "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.
{
  "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.
{
  "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).
{
  "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.
{
  "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.
{
  "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.
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);
The signing secret is displayed only once. Store it securely. You need it to verify incoming webhook requests.

Handle sending events

Use the same signature verification flow described in handle webhook events. Here is a condensed example handling sending events:
// 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