> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# 预览重新提交邮件

> 在 Didit 中预览重新提交请求的收件人、发件人、本地化邮件内容和验证链接，确认无误后再发送。

预览不会更改会话，也不会发送邮件。
查看响应后，请使用 [更新会话状态](https://docs.didit.me/zh/sessions-api/update-status.md) 进行确认，并将返回的 `preview_token` 作为 `email_preview_token` 传入。
回执 15 分钟后过期。
回执已更改或已过期时，接口会在修改会话或发送邮件之前返回 `409`。
发生冲突后，请重新生成预览。
现有 API 集成可以省略回执；在控制台中确认预览时，控制台会自动提供回执。

发件人和品牌信息遵循您现有的[白标配置](https://docs.didit.me/zh/console/white-label.md)。
邮件内容来自已翻译的验证模板；模板输入不接受任意主题、邮件正文或操作 URL。

## 谁会收到邮件

`email_address` 为可选项。
如果未传入，邮件将发送到用户本人的邮箱：即其在流程中通过邮箱验证步骤验证的地址；若没有，则使用创建会话时 `contact_details` 中提供的地址。
您在 `email_address` 中传入的地址优先。

`recipient_source` 用于说明适用的是哪个地址：

| `recipient_source` | `recipient` 的来源 |
| - | - |
| `email_verification` | 用户在流程中验证的地址 |
| `contact_details` | 创建会话时在 `contact_details` 中提供的地址 |
| `request` | 您传入的 `email_address` |
| `""`（空） | 没有已知地址：`recipient` 和 `preview_token` 为空，无法发送邮件 |

## 是否会发送邮件

使用 `send_email: true` 确认重新提交时，若会发送邮件，则 `will_be_sent` 为 `true`。
为 `false` 时，`not_sent_reason` 说明原因：

| `not_sent_reason` | 含义 |
| - | - |
| `no_user_action` | 所选的每个步骤都无需用户参与即可运行（例如 AML 筛查或数据库核验），因此重新提交会自动完成，且不会发送邮件。`requires_user_action` 同样为 `false`。 |
| `no_recipient` | 没有该用户的已知地址，且您也未传入地址。 |
| `sandbox` | 该会话为沙盒会话，且收件人未选择接收沙盒邮件，因此邮件仅为模拟发送。参见[邮件选择加入](https://docs.didit.me/zh/integration/sandbox-testing.md#otp-验证码与邮件选择加入)。 |

## 确认重新提交

使用以下字段调用[更新会话状态](https://docs.didit.me/zh/sessions-api/update-status.md)：

| 更新会话状态字段 | 值 |
| - | - |
| `new_status` | `Resubmitted` |
| `nodes_to_resubmit` | 与您在预览中使用的选择相同（如果您在预览中省略了该字段，此处也省略） |
| `send_email` | `true` |
| `email_address` | 预览中的 `recipient` |
| `email_language` | 与您传给预览的 `email_language` 相同 |
| `email_preview_token` | 预览中的 `preview_token` |

响应中的 `language` 表示邮件所用的语言：当您请求的语言不可用时，为英语。

## 重复的仅后端重新提交

当需要重新提交的所有步骤都无需用户参与（AML 筛查、数据库核验或 IP 分析）时，每 30 秒只能为用户重新提交一次会话。
在该时间窗口内，预览会返回 `429`，与更新会话状态的行为一致，等待时间通过 `Retry-After` 响应头返回。

## 相关内容

* [更新会话状态](https://docs.didit.me/zh/sessions-api/update-status.md)：确认重新提交。
* [预览决策邮件](https://docs.didit.me/zh/sessions-api/preview-decision-email.md)：改为预览“已通过”或“已拒绝”邮件。
* [白标](https://docs.didit.me/zh/console/white-label.md)：邮件所使用的发件人和品牌信息。


## OpenAPI

````yaml zh/openapi-25.json POST /v3/session/{sessionId}/resubmission-preview/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: 身份证件验证 API。使用 x-api-key 请求头进行身份验证。
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/session/{sessionId}/resubmission-preview/:
    post:
      tags:
        - Sessions
      summary: 预览重新提交电子邮件
      description: >-
        渲染 KYC 或 KYB 重新提交时将附带的邮件，且不会更改会话、重置检查、延长到期时间、运行检查或发送邮件。需要
        `write:sessions` 权限（受限范围的 API 密钥需要对决策拥有写入权限），且会话需处于
        `Approved`、`Declined`、`In Review`、`Kyc Expired` 或 `Abandoned`
        状态。服务器会验证所选的工作流步骤，并使用适用的已验证白标发件人和品牌标识渲染其固定的已翻译模板。请求中无法设置主题、正文或操作 URL。


        `email_address` 为可选参数。若未提供，邮件将发送至该人员自己的地址：即其在该工作流的邮箱验证步骤中核验的地址，或者在创建会话时于
        `contact_details` 中提供的地址。若您传入地址，则以您传入的为准（`recipient_source:
        request`）。当没有任何已知地址且您未传入地址时，`recipient` 和 `preview_token`
        将为空字符串，且无法发送任何邮件。


        响应包含收件人及其来源、发件人、主题、HTML、语言、已解析的步骤、确认后是否会发送邮件（`will_be_sent`、`not_sent_reason`）以及签名的
        `preview_token`。当所有选定的步骤都无需该人员参与即可运行时，`requires_user_action` 为
        `false`：重新提交将自动完成，且不会发送任何邮件（`not_sent_reason: no_user_action`）。


        此预览不会预留会话状态，也不会授权投递。检查预览后，调用
        [更新会话状态](/zh/sessions-api/update-status)，并传入 `new_status:
        Resubmitted`、与预览相同的 `nodes_to_resubmit` 和 `email_language`、`send_email:
        true`、设置为 `recipient` 的 `email_address` 以及设置为 `preview_token` 的
        `email_preview_token`。回执在 15
        分钟后过期。若提供了回执，在进行任何变更或发送之前，输入、消息内容、发件人或会话状态发生更改时，都会返回
        `409`。现有的集成可以省略回执。发生冲突后请重新生成预览。请将响应视为敏感验证内容；响应使用 `Cache-Control:
        no-store`。请在沙盒框架中渲染 HTML，切勿直接在您的应用 DOM 中渲染。
      operationId: post_v3_session_resubmission_preview
      parameters:
        - in: path
          name: sessionId
          required: true
          description: 要更新的验证会话的 UUID。支持用户（KYC）和企业（KYB）会话 ID，服务会跨两种会话类型解析该 ID。
          schema:
            type: string
            format: uuid
            example: 11111111-2222-3333-4444-555555555555
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                nodes_to_resubmit:
                  type: array
                  description: 要预览的步骤，使用与重新提交相同的验证、选择和工作流排序。省略此项将自动选择需要重新提交的已记录尝试。
                  items:
                    type: object
                    required:
                      - node_id
                      - feature
                    properties:
                      node_id:
                        type: string
                        description: >-
                          在会话的工作流定义中显示的节点标识符（例如
                          `feature_ocr`、`feature_liveness`）。
                        example: feature_ocr
                      feature:
                        type: string
                        description: >-
                          节点的功能类型。别名 `ID_VERIFICATION`、`POA`、`PHONE` 和 `EMAIL`
                          会在服务端规范化为
                          `OCR`、`PROOF_OF_ADDRESS`、`PHONE_VERIFICATION` 和
                          `EMAIL_VERIFICATION`。`KYB_REGISTRY`、`KYB_KEY_PEOPLE` 和
                          `KYB` 虽然能通过模式验证，但始终会被示例中所示的业务规则 `400` 拒绝。
                        enum:
                          - OCR
                          - OCR_BACK
                          - NFC
                          - AML
                          - FACE
                          - LIVENESS
                          - FACE_MATCH
                          - IP_ANALYSIS
                          - AGE_ESTIMATION
                          - PROOF_OF_ADDRESS
                          - PHONE_VERIFICATION
                          - EMAIL_VERIFICATION
                          - FACE_SEARCH
                          - DATABASE_VALIDATION
                          - QUESTIONNAIRE
                          - DOCUMENT_AI
                          - KYB_DOCUMENTS
                          - ID_VERIFICATION
                          - POA
                          - PHONE
                          - EMAIL
                          - KYB_REGISTRY
                          - KYB_KEY_PEOPLE
                          - KYB
                          - GEOLOCATION
                        example: OCR
                email_address:
                  type: string
                  format: email
                  description: >-
                    可选。将邮件发送至此地址，而非此人的地址。如未提供，收件人为该人在流程中验证的地址，否则为
                    `contact_details` 中提供的地址。此调用不会发送邮件。
                  example: user@example.com
                email_language:
                  type: string
                  description: 通知邮件的语言。在 schema 层面接受任何字符串；不支持的代码将以静默方式回退为英语（`en`）。
                  default: en
                  example: en
            examples:
              Person's Own Address:
                summary: 预览针对用户本人地址的地址证明重新提交
                value:
                  nodes_to_resubmit:
                    - node_id: feature_poa_1
                      feature: POA
                  email_language: en
              Named Recipient:
                summary: 预览指定地址的电子邮件
                value:
                  nodes_to_resubmit:
                    - node_id: feature_ocr
                      feature: OCR
                  email_address: person@example.com
                  email_language: en
      responses:
        '200':
          description: 仅供预览。会话保持不变且不会发送电子邮件。
          content:
            application/json:
              schema:
                type: object
                required:
                  - recipient
                  - recipient_source
                  - sender
                  - sender_name
                  - sender_email
                  - sender_kind
                  - subject
                  - html
                  - text
                  - language
                  - will_be_sent
                  - not_sent_reason
                  - preview_token
                  - nodes_to_resubmit
                  - requires_user_action
                properties:
                  recipient:
                    type: string
                    description: >-
                      邮件发送的目标地址。若该人员无已知地址，则为空字符串：此时无法发送邮件，且 `preview_token`
                      同样为空。确认时请将其作为 `email_address` 传递。
                    example: person@example.com
                  recipient_source:
                    type: string
                    enum:
                      - email_verification
                      - contact_details
                      - request
                      - ''
                    description: >-
                      `recipient` 的来源。`request`：您传递的
                      `email_address`。`email_verification`：用户在流程的邮箱验证步骤中验证的地址。`contact_details`：创建会话时在
                      `contact_details` 中提供的地址。没有地址时为空字符串。
                    example: email_verification
                  sender:
                    type: string
                    description: 发送邮件时使用的 `From` 请求头。
                    example: Example App <no-reply@mail.example.com>
                  sender_name:
                    type: string
                    description: '`sender` 的显示名称部分。'
                    example: Example App
                  sender_email:
                    type: string
                    format: email
                    description: '`sender` 的地址部分。'
                    example: no-reply@mail.example.com
                  sender_kind:
                    type: string
                    enum:
                      - customer
                      - didit
                    description: '`customer`：邮件从您应用的已验证发送方域名发出（白标）。`didit`：从 Didit 自己的发送方发出。'
                    example: customer
                  subject:
                    type: string
                    description: 与发送时完全一致的主题行。
                    example: 'Action Required: Complete your verification in Example App'
                  html:
                    type: string
                    description: >-
                      发送时完全一致的电子邮件 HTML，其徽标作为 data URL 嵌入。请在沙盒 frame
                      中渲染，切勿直接在您的应用 DOM 中渲染。
                    example: <!DOCTYPE html><html><body>...</body></html>
                  text:
                    type: string
                    description: 电子邮件的纯文本内容，与该用户的“消息”会话中保留的一致，用于紧凑预览（HTML 仍为该用户收到的电子邮件形式）。
                    example: |-
                      Almost there

                      Some steps need to be completed again.
                      Here’s what to fix:

                      https://verify.didit.me/session/abc123
                  language:
                    type: string
                    description: 邮件所用的语言。如果您请求的 `email_language` 不支持，则为英语（`en`）。
                    example: en
                  will_be_sent:
                    type: boolean
                    description: >-
                      使用 `send_email: true` 确认更改是否会发送此电子邮件。当设置了
                      `not_sent_reason` 时为 `false`。
                    example: true
                  not_sent_reason:
                    type: string
                    nullable: true
                    enum:
                      - no_user_action
                      - no_recipient
                      - sandbox
                      - null
                    description: >-
                      确认操作不会发送电子邮件的原因；若将发送邮件，则为
                      `null`。`no_user_action`：所有选定步骤均无需该用户参与即可运行，因此重新提交会自动完成且不发送任何电子邮件。`no_recipient`：未获知该用户的地址，且您未传入任何地址。`sandbox`：接收者未选择接收沙盒邮件投递的沙盒会话，因此发送仅为模拟。
                    example: null
                  nodes_to_resubmit:
                    type: array
                    items:
                      type: object
                      required:
                        - node_id
                        - feature
                      properties:
                        node_id:
                          type: string
                          description: >-
                            在会话的工作流定义中显示的节点标识符（例如
                            `feature_ocr`、`feature_liveness`）。
                          example: feature_ocr
                        feature:
                          type: string
                          description: >-
                            节点的功能类型。别名 `ID_VERIFICATION`、`POA`、`PHONE` 和 `EMAIL`
                            会在服务端规范化为
                            `OCR`、`PROOF_OF_ADDRESS`、`PHONE_VERIFICATION` 和
                            `EMAIL_VERIFICATION`。`KYB_REGISTRY`、`KYB_KEY_PEOPLE`
                            和 `KYB` 虽然能通过模式验证，但始终会被示例中所示的业务规则 `400` 拒绝。
                          enum:
                            - OCR
                            - OCR_BACK
                            - NFC
                            - AML
                            - FACE
                            - LIVENESS
                            - FACE_MATCH
                            - IP_ANALYSIS
                            - AGE_ESTIMATION
                            - PROOF_OF_ADDRESS
                            - PHONE_VERIFICATION
                            - EMAIL_VERIFICATION
                            - FACE_SEARCH
                            - DATABASE_VALIDATION
                            - QUESTIONNAIRE
                            - DOCUMENT_AI
                            - KYB_DOCUMENTS
                            - ID_VERIFICATION
                            - POA
                            - PHONE
                            - EMAIL
                            - KYB_REGISTRY
                            - KYB_KEY_PEOPLE
                            - KYB
                            - GEOLOCATION
                          example: OCR
                  requires_user_action:
                    type: boolean
                    description: 所选检查中是否至少有一项需要用户交互。这并不预示最终的工作流结果。
                  preview_token:
                    type: string
                    description: >-
                      此特定邮件的签名收据，有效期为 15 分钟。将其作为 `email_preview_token`
                      传递给[更新会话状态](/zh/sessions-api/update-status)。当没有收件人时为空字符串。
                    example: >-
                      eyJkaWdlc3QiOiI0ZjJhIn0:1uExAm:Pl3x4mpleS1gnatureValue000000000000000
              examples:
                Will Be Sent:
                  summary: 默认接收方：在流程中验证过的地址
                  value:
                    recipient: person@example.com
                    recipient_source: email_verification
                    sender: Example App <no-reply@mail.example.com>
                    sender_name: Example App
                    sender_email: no-reply@mail.example.com
                    sender_kind: customer
                    subject: 'Action Required: Complete your verification in Example App'
                    html: <!DOCTYPE html><html><body>...</body></html>
                    language: en
                    will_be_sent: true
                    not_sent_reason: null
                    nodes_to_resubmit:
                      - node_id: feature_poa_1
                        feature: PROOF_OF_ADDRESS
                    requires_user_action: true
                    preview_token: >-
                      eyJkaWdlc3QiOiI0ZjJhIn0:1uExAm:Pl3x4mpleS1gnatureValue000000000000000
                No User Action:
                  summary: 仅选择了后端步骤，因此不会发送电子邮件
                  value:
                    recipient: person@example.com
                    recipient_source: contact_details
                    sender: Example App <no-reply@mail.example.com>
                    sender_name: Example App
                    sender_email: no-reply@mail.example.com
                    sender_kind: customer
                    subject: 'Action Required: Complete your verification in Example App'
                    html: <!DOCTYPE html><html><body>...</body></html>
                    language: en
                    will_be_sent: false
                    not_sent_reason: no_user_action
                    nodes_to_resubmit:
                      - node_id: feature_aml
                        feature: AML
                    requires_user_action: false
                    preview_token: >-
                      eyJkaWdlc3QiOiI0ZjJhIn0:1uExAm:Pl3x4mpleS1gnatureValue000000000000000
          headers:
            Cache-Control:
              description: 始终为 `no-store`：预览包含验证内容，切勿缓存。
              schema:
                type: string
                example: no-store
        '400':
          description: 会话未处于此 endpoint 接受的状态、已处于 `Resubmitted` 状态、所选步骤无法重新提交，或某个字段无效。
          content:
            application/json:
              examples:
                Wrong Current Status:
                  summary: 会话不处于此 endpoint 接受的状态
                  value:
                    detail: >-
                      Only sessions with status Approved, Declined, In Review,
                      Kyc Expired, Abandoned, Resubmitted can be updated.
                      Current status: In Progress
                Already Resubmitted:
                  summary: 会话已处于 Resubmitted 状态
                  value:
                    - The new status is the same as the current status.
                Nothing To Resubmit:
                  summary: 自动选择未找到需要重新提交的步骤
                  value:
                    nodes_to_resubmit: >-
                      No features found that need resubmission. All features are
                      already approved.
                Invalid Email:
                  summary: email_address 不是有效的邮箱地址
                  value:
                    email_address:
                      - Enter a valid email address.
        '401':
          description: 作用域 API 密钥已过期。
          content:
            application/json:
              examples:
                Expired API Key:
                  summary: 已过有效期的作用域 API 密钥
                  value:
                    detail: This API key has expired.
        '403':
          description: >-
            缺少凭据、调用方没有 `write:sessions` 权限、限定范围的 API 密钥缺少此 endpoint 所需的访问权限，或者
            `session_id` 属于另一个应用。
          content:
            application/json:
              examples:
                Invalid Credentials:
                  summary: x-api-key 缺失或无效
                  value:
                    detail: >-
                      Authentication credentials were not provided or are
                      invalid.
                Missing Privilege:
                  summary: 调用方缺少 write:sessions 权限
                  value:
                    detail: You do not have permission to perform this action.
                Scoped Key Without Access:
                  summary: 没有此访问权限的作用域 API 密钥
                  value:
                    detail: This API key has no write access to decisions.
        '404':
          description: 不存在具有此 `session_id` 的 KYC 或 KYB 会话。
          content:
            application/json:
              examples:
                Not Found:
                  summary: 未知的 session_id
                  value:
                    detail: Not found.
        '429':
          description: >-
            要重新提交的步骤全为仅后端步骤（AML、DATABASE_VALIDATION、IP_ANALYSIS），且会话在过去 30
            秒内已经重新提交过仅后端步骤，因此 Update Session Status 会拒绝本次重新提交。请在 `Retry-After`
            指定的时间间隔后重试。
          content:
            application/json:
              examples:
                Backend-only resubmit throttled:
                  value:
                    detail: >-
                      This session was already resubmitted for backend-only
                      features within the last 30 seconds; repeating it cannot
                      change the outcome. Wait before resubmitting again.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.sessions.preview_resubmission(
                "11111111-2222-3333-4444-555555555555",
                nodes_to_resubmit=[{
                    "node_id": "feature_poa_1",
                    "feature": "POA",
                }],
                email_language="en",
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: >-
            import Didit from "@didit-protocol/sdk-node";


            // Reads DIDIT_API_KEY.

            const didit = new Didit();


            const result = await
            didit.sessions.previewResubmission("11111111-2222-3333-4444-555555555555",
            {
              nodes_to_resubmit: [{
                node_id: "feature_poa_1",
                feature: "POA",
              }],
              email_language: "en",
            });

            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Sessions.PreviewResubmission(ctx, \"11111111-2222-3333-4444-555555555555\", didit.SessionsPreviewResubmissionParams{\n\tNodesToResubmit: didit.Some([]didit.SessionsPreviewResubmissionParamsNodesToResubmit{{\n\t\tNodeID:  \"feature_poa_1\",\n\t\tFeature: \"POA\",\n\t}}),\n\tEmailLanguage: didit.String(\"en\"),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.util.List;

            import me.didit.Didit;

            import me.didit.types.SessionsPreviewResubmissionParams;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.sessions().previewResubmission("11111111-2222-3333-4444-555555555555",
            SessionsPreviewResubmissionParams.builder()
                    .nodesToResubmit(List.of(SessionsPreviewResubmissionParams.NodesToResubmit.builder()
                            .nodeId("feature_poa_1")
                            .feature(SessionsPreviewResubmissionParams.NodesToResubmit.Feature.of("POA"))
                            .build()))
                    .emailLanguage("en")
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: >-
            <?php


            require 'vendor/autoload.php';


            use Didit\DiditClient;


            // Reads DIDIT_API_KEY.

            $didit = new DiditClient();


            $result =
            $didit->sessions->previewResubmission('11111111-2222-3333-4444-555555555555',
            [
                'nodes_to_resubmit' => [[
                    'node_id' => 'feature_poa_1',
                    'feature' => 'POA',
                ]],
                'email_language' => 'en',
            ]);

            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.sessions.preview_resubmission(
              "11111111-2222-3333-4444-555555555555",
              nodes_to_resubmit: [{
                node_id: "feature_poa_1",
                feature: "POA",
              }],
              email_language: "en"
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await
            client.Sessions.PreviewResubmissionAsync("11111111-2222-3333-4444-555555555555",
            new SessionsPreviewResubmissionParams

            {
                NodesToResubmit = new SessionsPreviewResubmissionParamsNodesToResubmit[]
                {
                    new()
                    {
                        NodeId = "feature_poa_1",
                        Feature = "POA",
                    },
                },
                EmailLanguage = "en",
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        您的应用 API 密钥，可在 Business Console 的“开发者 -> API
        密钥”中获取。主密钥拥有完整访问权限。指定名称的密钥可设置作用域：针对每个资源设为无权限、只读或读写，限定于特定工作流或已通过的会话、限定于
        IP 地址列表，以及设置到期日期。401 表示密钥错误、已撤销或已过期；403 表示未发送密钥、密钥无权访问该资源或操作，或请求来自其 IP
        列表之外的地址；在会话路由上返回 404 表示该会话不在该密钥允许的工作流或状态范围内。没有媒体访问权限的密钥获取到的图片、视频和 PDF
        URL 将为 null；没有会话写入权限的密钥获取到的会话链接和 token 将为 null。请参阅
        https://docs.didit.me/console/api-keys。

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.