Events & Lifecycle

Understand how Postject tracks the delivery lifecycle of every email from queue to inbox.


Event Lifecycle

Every email sent through Postject generates a series of events as it moves through the delivery pipeline. The following diagram shows the possible paths a message can take:

text
Queued → Sent → Delivered
              ↘ Bounced
              ↘ Complained
         ↘ Rejected
         ↘ Failed
Supplementary: Opened, Clicked

The happy path is Queued, then Sent, then Delivered. At any point after being sent, a message may instead bounce, receive a complaint, or fail. If a message is rejected before it ever leaves Postject (e.g., suppressed address), it moves directly to Rejected without a Sent event. Supplementary events like Opened and Clicked may occur after delivery but do not change the message status.


Event Types

The following table describes every event type that Postject tracks:

Event TypeDescription
sentThe message was successfully transmitted to the recipient's mail server via Amazon SES.
deliveredThe recipient's mail server confirmed successful receipt of the message.
bouncedThe message was rejected by the recipient's mail server. Metadata includes the bounce type (hard or soft) and diagnostic code.
complainedThe recipient reported the email as spam. The address is automatically added to the suppression list for the stream.
rejectedThe message was rejected before sending. Common reasons: suppressed address, unverified sender identity, or account-level sending limits.
failedThe message could not be sent due to an internal processing error. The event metadata contains diagnostic information.
openedThe recipient opened the email. Tracked via an invisible pixel embedded in the HTML. May not fire if images are blocked.
clickedThe recipient clicked a link in the email. Tracked via link wrapping. Metadata includes the original URL that was clicked.

SES Integration

Postject uses Amazon SES as its underlying mail transport. Delivery events are received via Amazon SNS notifications, which Postject processes and maps to its own event types in real time.

The following table shows how SES event types map to Postject event types:

Amazon SES EventPostject Event
Sendsent
Deliverydelivered
Bouncebounced
Complaintcomplained
Rejectrejected
Rendering Failurefailed
Openopened
Clickclicked

Processing Latency

SES notifications are typically received within seconds of the event occurring. Postject processes these notifications in real time and updates the message status and event history immediately. Webhook notifications for these events are dispatched as soon as processing is complete.


Terminal vs Supplementary Events

Postject categorizes events into two groups based on how they affect the message status:

Terminal Events

Terminal events update the message's status field to reflect the final delivery outcome. Once a terminal event occurs, the message status is considered resolved.

deliveredbouncedcomplainedrejectedfailed

Supplementary Events

Supplementary events are tracked in the message's event history but do not change the message status. These events provide engagement data and are available via the API and webhooks.

openedclicked

For example, a message with status delivered may later receive opened and clicked events, but its status remains delivered.


Get Stream Events

Returns the most recent events for a given message stream, ordered by timestamp (newest first). Each event includes its parent message object for context. Returns the last 50 events by default. Requires JWT Bearer authentication.

GEThttps://api.postject.com/v1/events/streams/:id
json
[
  {
    "id": "evt_m3n4o5p6q7r8",
    "type": "opened",
    "timestamp": "2025-07-15T15:10:22.000Z",
    "metadata": {
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
      "ipAddress": "203.0.113.42"
    },
    "message": {
      "id": "msg_01hy4z8k2a3b4c5d",
      "to": "alice@example.com",
      "subject": "Your order has been shipped",
      "status": "delivered"
    }
  },
  {
    "id": "evt_g7h8i9j0k1l2",
    "type": "delivered",
    "timestamp": "2025-07-15T14:32:03.789Z",
    "metadata": {
      "smtpResponse": "250 2.0.0 OK",
      "processingTimeMs": 2333
    },
    "message": {
      "id": "msg_01hy4z8k2a3b4c5d",
      "to": "alice@example.com",
      "subject": "Your order has been shipped",
      "status": "delivered"
    }
  },
  {
    "id": "evt_s9t0u1v2w3x4",
    "type": "bounced",
    "timestamp": "2025-07-15T14:28:02.100Z",
    "metadata": {
      "bounceType": "Permanent",
      "bounceSubType": "General",
      "diagnosticCode": "smtp; 550 5.1.1 The email account does not exist"
    },
    "message": {
      "id": "msg_02iz5a9l3b4c5d6e",
      "to": "invalid@example.com",
      "subject": "Password reset request",
      "status": "bounced"
    }
  },
  {
    "id": "evt_a1b2c3d4e5f6",
    "type": "sent",
    "timestamp": "2025-07-15T14:28:00.892Z",
    "metadata": {
      "sesMessageId": "010201900a1b2c3d-4e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b-000000"
    },
    "message": {
      "id": "msg_02iz5a9l3b4c5d6e",
      "to": "invalid@example.com",
      "subject": "Password reset request",
      "status": "bounced"
    }
  }
]