---
title: "Get delivery attempts"
method: GET
path: "/emails/{emailId}/deliveries"
tags: ["Emails"]
---

# Get delivery attempts

`GET /emails/{emailId}/deliveries`

## Request

- Base URL: `https://api.arkhq.io/v1`
- URL: `https://api.arkhq.io/v1/emails/{emailId}/deliveries`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/arkhq-io/apis/ark-email-api/docs/emails/:emailId/deliveries/get.ts> (a function with typed inputs; its response is checked against the schema)

Get the complete delivery history for an email, including SMTP response codes,
timestamps, and current retry state.

## Response Fields

### Status
The current status of the email:
- `pending` - Awaiting first delivery attempt
- `sent` - Successfully delivered to recipient server
- `softfail` - Temporary failure, automatic retry scheduled
- `hardfail` - Permanent failure, will not retry
- `held` - Held for manual review
- `bounced` - Bounced by recipient server

### Retry State
When the email is in the delivery queue (`pending` or `softfail` status),
`retryState` provides information about the retry schedule:
- `attempt` - Current attempt number (0 = first attempt)
- `maxAttempts` - Maximum attempts before hard-fail (typically 18)
- `attemptsRemaining` - Attempts left before hard-fail
- `nextRetryAt` - When the next retry is scheduled (Unix timestamp)
- `processing` - Whether the email is currently being processed
- `manual` - Whether this was triggered by a manual retry

When the email has finished processing (`sent`, `hardfail`, `held`, `bounced`),
`retryState` is `null`.

### Can Retry Manually
Indicates whether you can call `POST /emails/{emailId}/retry` to manually retry
the email. This is `true` when the raw message content is still available
(not expired due to retention policy).

## Path parameters

- `emailId` string, required

## Response `200`

Delivery history with retry state

- DeliveriesResponse
  - `success` true, required
  - `data` object, required
    - `id` string, required: Message identifier (token)
    - `status` 'pending' | 'sent' | 'softfail' | 'hardfail' | 'held' | 'bounced', required: Current message status (lowercase). Possible values: - `pending` - Initial state, awaiting first delivery attempt - `sent` - Successfully delivered - `softfail` - Temporary failure, will retry automatically - `hardfail` - Permanent failure, will not retry - `held` - Held for manual review (suppression list, etc.) - `bounced` - Bounced by recipient server
    - `retryState` RetryState, required: Information about the current retry state of a message that is queued for delivery. Only present when the message is in the delivery queue.
      - `attempt` integer, required: Current attempt number (0-indexed). The first delivery attempt is 0, the first retry is 1, and so on.
      - `maxAttempts` integer, required: Maximum number of delivery attempts before the message is hard-failed. Configured at the server level.
      - `attemptsRemaining` integer, required: Number of attempts remaining before the message is hard-failed. Calculated as `maxAttempts - attempt`.
      - `nextRetryAt` number, nullable: Unix timestamp of when the next retry attempt is scheduled. `null` if the message is ready for immediate processing or currently being processed.
      - `nextRetryAtIso` string, date-time, nullable: ISO 8601 formatted timestamp of the next retry attempt. `null` if the message is ready for immediate processing.
      - `processing` boolean, required: Whether the message is currently being processed by a delivery worker. When `true`, the message is actively being sent.
      - `manual` boolean, required: Whether this queue entry was created by a manual retry request. Manual retries bypass certain hold conditions like suppression lists.
    - `canRetryManually` boolean, required: Whether the message can be manually retried via `POST /emails/{emailId}/retry`. `true` when the raw message content is still available (not expired). Messages older than the retention period cannot be retried.
    - `deliveries` Delivery[], required: Chronological list of delivery attempts for this message. Each attempt includes SMTP response codes and timestamps.
      - `id` string, required: Delivery attempt ID
      - `status` string, required: Delivery status (lowercase)
      - `details` string: Human-readable delivery summary. Format varies by status: - **sent**: `Message for {recipient} accepted by {ip}:{port} ({hostname})` - **softfail/hardfail**: `{code} {classification}: Delivery to {recipient} failed at {ip}:{port} ({hostname})`
      - `output` string: Raw SMTP response from the receiving mail server
      - `code` integer: SMTP response code
      - `sentWithSsl` boolean: Whether TLS was used
      - `timestamp` number, required: Unix timestamp
      - `timestampIso` string, date-time, required: ISO 8601 timestamp
      - `classification` 'invalid_recipient' | 'mailbox_full' | 'message_too_large' | 'spam_block' | 'policy_violation' | 'no_mailbox' | 'not_accepting_mail' | 'temporarily_unavailable' | 'protocol_error' | 'tls_required' | 'connection_error' | 'dns_error' | 'unclassified', nullable: Bounce classification category (present for failed deliveries). Helps understand why delivery failed for analytics and automated handling.
      - `classificationCode` integer, nullable: Numeric bounce classification code for programmatic handling. Codes: 10=invalid_recipient, 11=no_mailbox, 12=not_accepting_mail, 20=mailbox_full, 21=message_too_large, 30=spam_block, 31=policy_violation, 32=tls_required, 40=connection_error, 41=dns_error, 42=temporarily_unavailable, 50=protocol_error, 99=unclassified
      - `smtpEnhancedCode` string, nullable: RFC 3463 enhanced status code from SMTP response (e.g., "5.1.1", "4.2.2"). First digit: 2=success, 4=temporary, 5=permanent. Second digit: category (1=address, 2=mailbox, 7=security, etc.).
      - `remoteHost` string, nullable: Hostname of the remote mail server that processed the delivery. Present for all delivery attempts (successful and failed).
  - `meta` ApiMeta, required
    - `requestId` string, required: Unique request identifier for debugging and support

## Other responses

- `401`: Invalid or missing API key
- `404`: Resource not found
- `500`: Internal server error

## Changes

- **2026-02-08** `37bce0c9a4d7`: 3 warning, 3 info
  - added the new `infrastructure_error` enum value to the `error/code` response property for the response status `401`
  - added the new `infrastructure_error` enum value to the `error/code` response property for the response status `404`
  - added the new `infrastructure_error` enum value to the `error/code` response property for the response status `500`
  - removed the `postal_error` enum value from the `error/code` response property for the response status `401`
  - …2 more
- **2026-02-08** `4f8eeb0b9933`: 138 warning
  - added the new `already_exists` enum value to the `error/code` response property for the response status `401`
  - added the new `already_exists` enum value to the `error/code` response property for the response status `404`
  - added the new `already_exists` enum value to the `error/code` response property for the response status `500`
  - added the new `attachment_too_large` enum value to the `error/code` response property for the response status `401`
  - …134 more
- **2026-02-03** `13bda63d06ce`: 2 breaking, 1 info
  - removed the required property `data/messageId` from the response with the `200` status
  - removed the required property `data/messageToken` from the response with the `200` status
  - added the required property `data/id` to the response with the `200` status
- …earlier changes not shown

[Operation history](https://skmtc.dev/arkhq-io/apis/ark-email-api/changes/emails/:emailId/deliveries/get.md)

---

[API](https://skmtc.dev/arkhq-io/apis/ark-email-api.md) - [All operations](https://skmtc.dev/arkhq-io/apis/ark-email-api/llms.txt) - [OpenAPI document](https://skmtc.dev/arkhq-io/apis/ark-email-api/revisions/98a90852ffca?raw)
