# 邮件转发 API

> 项目的收件地址，以及转发进项目的邮件。

原文：https://qunli.co/docs/developers/api/email

由群历 REST API 的 OpenAPI 契约（`openapi/qunli-api.yaml`，qunli-api 提交 `f18e40d`）生成。路径都相对于 `https://qunli.co`；认证见[认证](https://qunli.co/docs/developers/authentication)，响应包装、分页和错误格式见[约定](https://qunli.co/docs/developers/conventions)。字段说明是契约里的英文原文。

## 收件地址

### `GET /api/v1/accounts/{account_id}/projects/{project_id}/email_forward`

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `project_id` | 路径 | string | 是 |  |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Email forward | `data`: `EmailForward` |
| `401` | Missing or invalid authentication. | `ProblemDetails` |

### `PATCH /api/v1/accounts/{account_id}/projects/{project_id}/email_forward`

Project admins and team owners/admins only; others get 403.

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `project_id` | 路径 | string | 是 |  |

请求体（`application/json`）：

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `regenerate` | boolean | 否 |  |
| `email_forward` | object | 否 |  |
| `email_forward.status` | string | 否 |  |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Updated email forward | `data`: `EmailForward` |
| `401` | Missing or invalid authentication. | `ProblemDetails` |
| `403` | Authenticated but not permitted. | `ProblemDetails` |

## 转发的邮件

### `GET /api/v1/accounts/{account_id}/projects/{project_id}/forwarded_emails`

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `project_id` | 路径 | string | 是 |  |
| `content` | 查询 | `full` \| `summary` | 否 | full (default): rows carry their whole body. summary: rows leave out content_html, content_json, content_markdown and content_version and carry only preview_text / excerpt (documents: also preview_html); read one record for its body. Other values → 400 param_invalid. 默认 `full`。 |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Forwarded emails | `data`: `ForwardedEmail`[] |
| `401` | Missing or invalid authentication. | `ProblemDetails` |

### `GET /api/v1/accounts/{account_id}/forwarded_emails/{id}`

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `id` | 路径 | string (ref) | 是 | 引用号，例如 `T1042`，大小写不敏感，可带前导 `#`。 |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Forwarded email | `data`: `ForwardedEmail` |
| `401` | Missing or invalid authentication. | `ProblemDetails` |
| `404` | Resource does not exist or has been trashed. | `ProblemDetails` |

### `GET /api/v1/accounts/{account_id}/projects/{project_id}/forwarded_emails/{id}`

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `project_id` | 路径 | string | 是 |  |
| `id` | 路径 | string (ref) | 是 | 引用号，例如 `T1042`，大小写不敏感，可带前导 `#`。 |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Forwarded email | `data`: `ForwardedEmail` |
| `401` | Missing or invalid authentication. | `ProblemDetails` |
| `404` | Resource does not exist or has been trashed. | `ProblemDetails` |

### `DELETE /api/v1/accounts/{account_id}/projects/{project_id}/forwarded_emails/{id}`

Soft-delete a forwarded email (returns the trashed recording)

参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `account_id` | 路径 | string | 是 | 团队的数字 id，和网页地址里的相同，例如 `2025`。 |
| `project_id` | 路径 | string | 是 |  |
| `id` | 路径 | string (ref) | 是 | 引用号，例如 `T1042`，大小写不敏感，可带前导 `#`。 |

响应：

| 状态 | 说明 | 返回 |
| --- | --- | --- |
| `200` | Trashed forwarded email | `data`: `ForwardedEmail` |
| `401` | Missing or invalid authentication. | `ProblemDetails` |
| `403` | Authenticated but not permitted. | `ProblemDetails` |
| `404` | Resource does not exist or has been trashed. | `ProblemDetails` |

## 数据结构

上面的响应用到的对象。字段的类型是另一个对象时，它也列在这里。

### EmailForward

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string (uuid) | 是 |  |
| `project_id` | string (uuid) | 是 |  |
| `email_address` | string | 是 |  |
| `status` | string | 是 |  |
| `created_at` | string (date-time) | 是 |  |
| `updated_at` | string (date-time) | 是 |  |

### ForwardedEmail

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string (uuid) | 是 |  |
| `public_id` | string \| null | 否 |  |
| `legacy_id` | string \| null | 是 |  |
| `title` | string | 是 |  |
| `content_html` | string \| null | 否 |  |
| `content_json` | object \| null | 否 |  |
| `content_markdown` | string \| null | 否 | Canonical body (GFM). content_html is rendered server-side from it; null on rows not yet migrated from Tiptap JSON. |
| `content_version` | integer | 否 | Body version for compare-and-set saves. Starts at 0 and increases by one each time content_markdown / content_html / content_json actually changes (any write path). Send it back as recording.content_version when saving a body edit. |
| `preview_text` | string | 否 | Lists only. The body as plain text (HTML tags removed, entities left encoded, e.g. "&amp;"), cut to 80 UTF-16 units; "" without a body. |
| `excerpt` | string \| null | 否 | Lists only. Up to 100 characters of the body's text, images and videos shown as [图片] / [视频]; null without a body. |
| `preview_html` | string | 否 | Document lists only. The first 3000 characters of content_html (may end inside a tag), for thumbnails. |
| `comments_count` | integer | 是 |  |
| `type` | string | 是 |  |
| `status` | `draft` \| `active` \| `archived` \| `trashed` | 是 |  |
| `recordable_type` | `ForwardedEmail` | 是 |  |
| `app_url` | string \| null | 是 |  |
| `account_id` | string (uuid) | 是 |  |
| `account_public_id` | string | 是 |  |
| `project_id` | string (uuid) | 是 |  |
| `project_public_id` | string | 是 |  |
| `creator_id` | string (uuid) | 是 |  |
| `parent_id` | string (uuid) \| null | 否 |  |
| `parent_public_id` | string \| null | 否 |  |
| `ancestors` | `FolderCrumb`[] | 否 |  |
| `created_at` | string (date-time) | 是 |  |
| `updated_at` | string (date-time) | 是 | Last change of the recording or of its body, whichever is later. |
| `reactions` | `Reaction`[] | 是 |  |
| `edited_by` | `UserRef` | 否 | Comments and discussions only: the last member other than the author who edited the title or body (the author's own later edits keep it); null when only the author edited it. |
| `trashed_by` | `UserRef` | 否 | Comments and discussions only: the member other than the author who trashed it; null otherwise (cleared by the author's own trash and on restore). A comment with status "trashed" and a trashed_by is a placeholder in GET .../recordings/:id/comments — its title and content are empty. |
| `sender_email` | string | 是 |  |
| `sender_name` | string \| null | 是 |  |
| `subject` | string \| null | 是 |  |
| `received_at` | string (date-time) | 是 |  |
| `files` | `AttachedFile`[] | 是 |  |

### FolderCrumb

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string (uuid) | 是 |  |
| `public_id` | string \| null | 是 |  |
| `title` | string | 是 |  |

### Reaction

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string (uuid) | 是 |  |
| `actor_id` | string (uuid) | 是 |  |
| `reactable_id` | string (uuid) | 是 |  |
| `reactable_type` | string | 是 |  |
| `reaction_type_id` | string (uuid) | 是 |  |
| `reaction_emoji` | string | 是 |  |
| `reaction_name` | string | 是 |  |
| `created_at` | string (date-time) | 是 |  |
| `updated_at` | string (date-time) | 是 |  |

### UserRef

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | string (uuid) | 是 | User UUID. |
| `public_id` | string \| null | 是 | Member ref ("U12") in this account. |
| `name` | string \| null | 是 |  |
| `avatar_url` | string \| null | 是 |  |
| `kind` | `human` \| `agent` \| null | 是 | null only for an unknown (deleted) user. |

### AttachedFile

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `id` | integer | 否 |  |
| `filename` | string | 否 |  |
| `content_type` | string \| null | 否 |  |
| `byte_size` | integer | 否 |  |
| `url` | string | 否 |  |
| `image` | boolean | 否 |  |
