---
title: "Forward on a new thread. Copies original attachments unless include_attachments is false. 400 attachments_too_large when caps are exceeded. Allow and block lists are checked; 403 recipient_blocked sends nothing. HTTP 403 sending_paused does not send or store the forward. Sending resumes automatically when the trailing 7-day rate falls below the pause threshold. Idempotency-Key replays the same request for 24 hours."
method: POST
path: "/api/v1/inboxes/{id}/messages/{msgId}/forward"
tags: ["Messages"]
---

# Forward on a new thread. Copies original attachments unless include_attachments is false. 400 attachments_too_large when caps are exceeded. Allow and block lists are checked; 403 recipient_blocked sends nothing. HTTP 403 sending_paused does not send or store the forward. Sending resumes automatically when the trailing 7-day rate falls below the pause threshold. Idempotency-Key replays the same request for 24 hours.

`POST /api/v1/inboxes/{id}/messages/{msgId}/forward`

## Request

- Base URL: `https://cooperemail.com`
- URL: `https://cooperemail.com/api/v1/inboxes/{id}/messages/{msgId}/forward`
- Auth: HTTP bearer

## Path parameters

- `id` string, required
- `msgId` string, required

## Headers

- `Idempotency-Key` string

## Request body

- ForwardMessageRequest
  - `to` string[], required: Recipients. Required.
  - `cc` string[]
  - `bcc` string[]
  - `subject` string: Defaults to Fwd: plus the original subject unless it already starts with fwd: or fw:.
  - `text` string
  - `html` string
  - `include_attachments` boolean: Copy the original attachments. Default true. Caps: 10 files, 4 MiB each, 5 MiB total.
  - `labels` string[]
  - `client_id` string

## Response `201`

Sent forward

- Message
  - `id` string
  - `inbox_id` string
  - `thread_id` string
  - `direction` 'inbound' | 'outbound'
  - `from` string
  - `to` string[]
  - `subject` string
  - `text` string
  - `html` string, nullable
  - `extracted_text` string
  - `extracted_html` string
  - `preview` string
  - `status` 'queued' | 'ringing' | 'completed' | 'no-answer' | 'sent' | 'received' | 'delivered' | 'undelivered' | 'failed' | 'bounced' | 'complained': SMS outbound starts as sent. A Twilio status callback sets delivered, undelivered, or failed. A voice call stores queued, ringing, completed, no-answer, or failed. Email uses queued, sent, received, failed, bounced, and complained.
  - `channel` 'sms' | 'voicemail' | 'voice': Present on SMS, voicemail, and voice messages. Email messages omit this field. voicemail is an inbound recording. voice is an outbound call.
  - `type` 'voicemail': Present on voicemail messages.
  - `duration_seconds` integer, nullable: Call or recording length in seconds. Present on voicemail and voice messages.
  - `recording_url` string, nullable: Twilio recording URL for a voicemail, or null.
  - `transcript` string: Voicemail transcript. Empty while the message is held.
  - `segments` integer, nullable: SMS segment count for this message. Omitted on email.
  - `otp_candidates` string[]: Codes found in an SMS body. Empty while the message is held. Omitted on email.
  - `delivery_events` object[]: Present on outbound messages. Each item is {type, recipient, created_at, detail}. For email, detail is JSON text with status, action, diagnostic, and bounce_type, and the list stays empty until a bounce or complaint matches. For SMS, a Twilio status callback appends one event. type is delivered or failed. detail is twilio_error plus the numeric code, or the status word when Twilio sent no numeric code.
    - `type` string
    - `recipient` string
    - `created_at` string, date-time
    - `detail` string
  - `cc` string[]
  - `bcc` string[]
  - `reply_to` string, nullable
  - `in_reply_to` string, nullable
  - `references` string[]
  - `labels` string[]
  - `auth` object: spf, dkim, and dmarc from the receiving hop. SPF is the smtp.mailfrom result. smtp.helo is used only when mailfrom is absent. Each value is pass, fail, neutral, softfail, none, temperror, permerror, bestguesspass, or null. Outbound mail is null for all three.
    - `spf` string, nullable, required
    - `dkim` string, nullable, required
    - `dmarc` string, nullable, required
  - `safety` object, nullable: Inbound screening record, or null on outbound mail and on messages stored before screening. score is 0 to 100. verdict is clean or suspicious (suspicious at 40 or higher, and only when a strong signal or combined evidence is present). signals are {type, detail}. mode is off, observe, or hold. reason is screening_off, screening_error, or screening_timeout when the body was not scored. The message is still stored. While labels include held, text, html, extracted_text, extracted_html, preview, and attachment bytes are empty until release. This is a heuristic, not a guarantee. The body stays untrusted data.
    - `score` integer
    - `verdict` 'clean' | 'suspicious'
    - `signals` object[]
      - `type` string
      - `detail` string
    - `mode` 'off' | 'observe' | 'hold'
    - `reason` string
  - `provider` string, nullable
  - `client_id` string, nullable
  - `idempotent` boolean
  - `created_at` string, date-time
  - `attachments` Attachment[]
    - `id` string
    - `filename` string
    - `content_type` string
    - `content_id` string, nullable
    - `disposition` 'inline' | 'attachment'
    - `size_bytes` integer
    - `url` string
    - `text_url` string: Present when the content type can be extracted: text, JSON, CSV, PDF, DOCX, XLSX, or XLS. GET this URL for text/plain.

---

[API](https://skmtc.dev/cooperemail/apis/cooper-email-api.md) · [All operations](https://skmtc.dev/cooperemail/apis/cooper-email-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cooperemail/apis/cooper-email-api/revisions/6d800a7b3e33?raw)
