Skip to content

Sendings ​

The Sending resource is Hantera's centralized communication queue system. It tracks queued messages (emails, and in the future: SMS, push notifications) through the entire delivery lifecycle with granular status tracking and automatic retries.

What is a Sending? ​

A Sending represents a single queued communication to a primary recipient. When you send an email using the sendEmail function, a Sending record is created to track delivery status, retries, and any errors that occur.

Key characteristics:

  • One record per primary recipient: Multi-recipient emails create one record for the to recipient; CC/BCC are best-effort delivery
  • Asynchronous processing: Messages are queued and processed in the background
  • Status tracking: Monitor pending, sent, and bounced messages via the Graph API
  • Rate limiting: Respects configured rate limits to avoid overwhelming mail servers
  • Automatic retries: Transient failures are automatically retried with exponential backoff (up to 3 times)

INFO

System Sendings: The Sending system is used both by apps (through sendEmail) and by Hantera's internal platform features (password resets, email validations, etc.). Platform-generated sendings use categories with the system: prefix (e.g., system:password_reset). This prefix is reserved and cannot be used in app-created sendings.

Creating Sendings ​

Sendings can be created in two ways depending on your use case:

Via Filtrera (Components/Reactors) ​

Use the sendEmail function in Filtrera for component logic:

filtrera
import 'resources'

from sendEmail {
  to = '[email protected]'
  subject = 'Order Confirmation'
  body = {
    plainText = 'Thank you for your order!'
    html = '<h1>Thank you for your order!</h1>'
  }
  category = 'order_confirmation'
  dynamic = {
    orderId = order.id
  }
}

See: sendEmail function documentation

Via REST API (External Applications) ​

For external applications, use the HTTP API:

bash
POST /resources/sendings/email
json
{
  "to": "[email protected]",
  "subject": "Order Confirmation",
  "body": {
    "plainText": "Thank you for your order!",
    "html": "<h1>Thank you for your order!</h1>"
  },
  "category": "order_confirmation",
  "dynamic": {
    "orderId": "12345"
  }
}

TIP

See the HTTP API Reference for complete REST API documentation including all endpoints, request/response schemas, and authentication requirements.

Lifecycle & Status ​

Each Sending progresses through these states:

pending ​

The message is queued and waiting to be processed by the background service. Pending sendings can be cancelled via the REST API.

sent ​

The message was successfully delivered to the mail server. Note that this indicates delivery to the mail server, not necessarily to the recipient's inbox.

bounced ​

Delivery failed after all retries were exhausted. Check the errorMessage field for details.

cancelled ​

The sending was cancelled before being processed. Only pending sendings can be cancelled using the DELETE /resources/sendings/{id} REST endpoint.

Transport Types ​

The transport field indicates the communication channel:

  • email: Email delivery (currently supported)
  • sms: SMS delivery (planned)
  • push: Push notification (planned)

Currently, only email transport is implemented.

Processing Behavior ​

INFO

Sendings are processed asynchronously by a background service. They are not sent immediately when created.

How it works:

  1. Queueing: When sendEmail is called, a Sending record is created with pending status
  2. Processing: Background service processes the queue every 10 seconds (configurable)
  3. Rate limiting: Default 60 emails/minute (configurable)
  4. Retries: Failed deliveries are retried up to 3 times with exponential backoff
  5. Final status: After retries, status becomes either sent or bounced

Multi-Recipient Behavior ​

When you provide cc or bcc lists:

  • One Sending record is created for the primary to recipient (with tracked status)
  • CC and BCC recipients receive the email as best-effort delivery
  • No individual tracking for CC/BCC recipients

The cc and bcc recipients are stored as comma-separated strings in the Sending record's data field, but do not have their own Sending records or status tracking.

Querying Sendings ​

Use the Graph API to query Sending records:

json
[
  {
    "edge": "sendings",
    "filter": "status == 'pending'",
    "orderBy": "createdAt desc",
    "node": {
      "fields": ["sendingId", "recipient", "category", "createdAt"]
    }
  }
]

See: Sending Graph Node for complete query documentation

Custom Data ​

Store queryable data in the dynamic field:

filtrera
import 'resources'

from sendEmail {
  to = customer.email
  subject = 'Campaign Offer'
  body = {
    html = '<p>Special offer just for you!</p>'
  }
  dynamic = {
    customerId = customer.id
    campaignId = campaign.id
    segmentId = segment.id
  }
}

Then define custom Graph fields to query this data:

yaml
uri: /resources/registry/graph/sending/fields/campaignId
spec:
  value:
    type: text
    source: dynamic->'campaignId'

Now you can query by campaign:

json
[
  {
    "edge": "sendings",
    "filter": "campaignId == '12345' and status == 'sent'",
    "count": true
  }
]

Access Control ​

Creating sendings requires the sendings:write permission:

sendings:write        # Create new sendings via sendEmail or REST API

Querying sendings uses the Graph API, which requires Graph-specific permissions:

graph/sending:query   # Query sending records
graph/sending:field   # Access specific fields

Managing sendings via REST requires:

sendings:write        # POST /resources/sendings/email (create)
sendings:read         # GET /resources/sendings/{id} (retrieve status)
sendings:write        # DELETE /resources/sendings/{id} (cancel)

INFO

The REST API provides endpoints for creating and managing sendings. For querying and analytics, use the Graph API. See Access Control for more on permission patterns.

REST API ​

The Sending resource includes a REST API for queueing, monitoring, and cancelling email delivery from external applications.

Available Endpoints ​

  • POST /resources/sendings/email - Queue an email for delivery
  • GET /resources/sendings/{id} - Retrieve sending status and details
  • DELETE /resources/sendings/{id} - Cancel a pending sending

TIP

See the HTTP API Reference for complete endpoint documentation including request/response schemas, error codes, and authentication requirements.

When to Use REST vs Filtrera ​

Use REST API when:

  • Building external integrations
  • Sending emails from non-Hantera environments
  • Need direct HTTP access without Filtrera runtime

Use Filtrera sendEmail when:

  • Writing automations using rules and jobs within Hantera
  • Building Hantera apps

Examples ​

For practical examples of using the Sendings REST API in real-world scenarios, see the Customer Registration for E-Commerce guide which demonstrates sending registration confirmations and password reset emails.

Cancelling Sendings ​

Only sendings with pending status can be cancelled. Attempting to cancel sent, bounced, or already cancelled sendings returns a 409 Conflict error.

bash
DELETE /resources/sendings/{sendingId}

Returns:

  • 204 No Content - Successfully cancelled
  • 404 Not Found - Sending does not exist
  • 409 Conflict - Sending status is not pending

Monitoring & Troubleshooting ​

Check Queue Depth ​

Monitor the number of pending sendings:

json
[
  {
    "edge": "sendings",
    "filter": "status == 'pending'",
    "count": true
  }
]

Health indicators:

  • Healthy: < 50 pending
  • Warning: 50-100 pending
  • Critical: > 100 pending

Find Recent Failures ​

json
[
  {
    "edge": "sendings",
    "filter": "status == 'bounced' and createdAt >= '2025-10-30T00:00:00Z'",
    "orderBy": "createdAt desc",
    "node": {
      "fields": ["sendingId", "recipient", "errorMessage", "retryCount", "category"]
    }
  }
]

Calculate Bounce Rate ​

json
[
  {
    "edge": "sendings",
    "alias": "total",
    "filter": "createdAt >= '2025-10-01T00:00:00Z'",
    "count": true
  },
  {
    "edge": "sendings",
    "alias": "bounced",
    "filter": "createdAt >= '2025-10-01T00:00:00Z' and status == 'bounced'",
    "count": true
  }
]

A bounce rate above 5% may indicate email list quality issues.

© 2026 Hantera AB. Org. no.: 559242-9582