service-email-to-case-configure

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Configure Email-to-Case (Metadata API)

配置Email-to-Case(Metadata API)

Configure Salesforce Email-to-Case entirely through the Metadata API (no Setup UI), for headless org configuration. The skill builds a
CaseSettings
source file for the desired
emailToCase
state, then applies it with
scripts/apply-casesettings.py
, which runs
updateMetadata
in two phases — the full
emailToCase
block + Support Settings (Phase A), then routing addresses (Phase B) — and verifies by re-reading. Two phases because a single deploy fails on a fresh org: On-Demand must be live before an address binds (see Rules / Constraints).
完全通过Metadata API(无需设置UI)配置Salesforce Email-to-Case,用于无头组织配置。该技能会为所需的
emailToCase
状态构建
CaseSettings
源文件,然后通过
scripts/apply-casesettings.py
应用配置——该脚本会分两个阶段运行
updateMetadata
:完整的
emailToCase
块+支持设置(阶段A),然后是路由地址(阶段B)——并通过重新读取进行验证。分两个阶段是因为在全新组织中单次部署会失败:必须先启用On-Demand才能绑定地址(请参阅规则/约束)。

Scope

范围

  • In scope: Enabling Email-to-Case org-wide and setting its toggles (full field lists in Required Inputs and step 4); creating
    EmailToCase
    ,
    Outlook
    , and
    GmailOAuth
    routing addresses; applying the change to an sf-CLI-authenticated org via
    apply-casesettings.py
    ; verifying by re-reading.
  • Out of scope:
    • E2cEasy
      routing addresses
      — created only through the Service Easy Setup wizard, not the Metadata API; route the user there.
    • Authenticating the org — the user authenticates out-of-band (e.g.
      sf org login web
      ); the script reuses that session and never handles passwords or tokens.
    • Case object schema, layouts, assignment rules, or Web-to-Case.

  • 包含范围:在组织层面启用Email-to-Case并设置其开关(必填输入和步骤4中有完整字段列表);创建
    EmailToCase
    Outlook
    GmailOAuth
    路由地址;通过
    apply-casesettings.py
    将更改应用到已通过sf CLI认证的组织;通过重新读取进行验证。
  • 排除范围
    • E2cEasy
      路由地址
      ——仅能通过Service Easy Setup向导创建,无法通过Metadata API创建;请引导用户使用该向导。
    • 组织认证——用户需通过外部方式完成认证(例如
      sf org login web
      );脚本会复用该会话,绝不会处理密码或令牌。
    • Case对象架构、布局、分配规则或Web-to-Case。

Attaching an Agentforce service agent (delegation)

绑定Agentforce服务代理(委托)

When the user wants an Agentforce Service Agent to answer these emails, configure the Email-to-Case base (the Workflow below), then delegate — this skill never creates or modifies agents.
Gate on org capability first. Attaching an agent needs the org entitled for Agentforce Email-to-Case; that entitlement surfaces as the
BotEmailDefinition
metadata type, so probe read-only before delegating:
bash
scripts/check-agent-email-capability.sh <target-org-alias>   # pins describe to the org's API version
Exit 3 → not entitled: stop, tell the user, and configure the plain Email-to-Case base only — make no Agentforce agent or channel-wiring changes. Any other non-zero is an unreachable org, not "not entitled" — fix auth and re-run. On exit 0, delegate:
  1. Agent creation →
    agentforce-generate
    ,
    omitting the Service Customer Verification topic (unsupported on the email channel) and including an Escalation subagent so the agent can hand off to a human — on email, escalation transfers the case to a service rep, and without the subagent the agent can't escalate.
  2. Wiring →
    service-agentforce-channel-configure
    Branch C.

当用户希望Agentforce服务代理处理这些邮件时,请先配置Email-to-Case基础设置(如下方工作流所示),然后进行委托——本技能绝不会创建或修改代理。
首先检查组织能力。绑定代理需要组织拥有Agentforce Email-to-Case的权限;该权限以
BotEmailDefinition
元数据类型的形式体现,因此在委托前需先进行只读探测:
bash
scripts/check-agent-email-capability.sh <target-org-alias>   # 将describe固定到组织的API版本
退出码3 → 无权限:停止操作,告知用户,仅配置纯Email-to-Case基础设置——请勿进行任何Agentforce代理或渠道连接的更改。其他非零退出码表示组织不可达,而非“无权限”——请修复认证后重新运行。退出码为0时,进行委托:
  1. 代理创建 →
    agentforce-generate
    ,省略Service Customer Verification主题(邮件渠道不支持),并包含升级子代理,以便代理可以将任务转交给人工——在邮件渠道中,升级会将案例转交给服务代表,若无子代理则代理无法进行升级操作。
  2. 渠道连接 →
    service-agentforce-channel-configure
    分支C

Required Inputs

必填输入

Gather or infer before applying. Ask only when a wrong assumption would produce a broken or incorrect result:
  • Target org alias — the sf CLI alias/username of an already-authenticated org. The script obtains the session with
    sf org display
    and
    sf org auth show-access-token
    ; it does not log in for you.
  • Routing address(es) — for each:
    routingName
    (unique label),
    addressType
    (
    EmailToCase
    default, or
    Outlook
    /
    GmailOAuth
    ),
    caseOrigin
    , and
    casePriority
    . The platform rejects the address if
    caseOrigin
    or
    casePriority
    is missing, so treat all four as required in the source file.
  • Customer-facing email address per routing addressask explicitly for each, in address order; never guess, default, or reuse from earlier context. Not stored in the source file — passed at apply time via
    --routing-email
    (one per address; the script fails closed on a count mismatch).
  • Support Settings — Default Case Owner & Automated Case User — preserve-first, never assumed:
    • Independent, preserved per field. Each configured field is left untouched; change one only if the user asks (
      --overwrite-support-settings
      ). Ask only for the field(s) unset.
    • For each unset field, ask (never default to the authenticated user): Default Case Owner type (
      User
      /
      Queue
      ) + value (active Username or Queue DeveloperName) →
      --owner-type
      /
      --owner-value
      ; Automated Case User type (
      User
      /
      System
      ) —
      User
      needs a username,
      System
      needs no value →
      --automated-type
      /
      --automated-value
      (+ optional
      --system-user-email
      for System when the org's automated user doesn't exist yet).
    • If any value is invalid, the script fails — get a valid value and re-run; never substitute or guess.
    • Pass
      --use-authenticated-user
      only if the user explicitly asks.
  • Case defaults per address (optional) —
    createTask
    ,
    saveEmailHeaders
    , and an optional per-address Default Case Owner (
    caseOwner
    +
    caseOwnerType
    ), opt-in per address (see step 6): omitted by default so cases fall to the org Default Case Owner / assignment rules. When set,
    caseOwner
    (active Username or Queue DeveloperName) must be paired with
    caseOwnerType
    (
    User
    /
    Queue
    ); the script validates it against the org, failing closed if absent.
  • Org-level toggles (optional) — set only if the user asks. Two containers: the
    emailToCase
    section
    (
    enableHtmlEmail
    ,
    notifyOwnerOnNewCaseEmail
    ,
    enableE2CDeduplicateAttachments
    ,
    showWordCountInComposer
    , plus
    enableE2CSourceTracking
    ,
    overEmailLimitAction
    ,
    unauthorizedSenderAction
    ), and top-level Support Settings (
    enableDraftEmails
    — plural element name, a sibling of
    emailToCase
    ). See step 4's table for container/UI-label mapping; top-level scalar toggles apply in Phase A.
Defaults:
enableEmailToCase
and
enableOnDemandEmailToCase
default to
true
(both required — On-Demand before routing addresses);
addressType
defaults to
EmailToCase
. Support Settings have no default — preserved if set, otherwise elicited (never the authenticated user).

在应用配置前收集或推断信息。仅当错误假设会导致配置损坏或不正确时才询问用户:
  • 目标组织别名——已认证组织的sf CLI别名/用户名。脚本通过
    sf org display
    sf org auth show-access-token
    获取会话;不会为用户执行登录操作。
  • 路由地址——每个地址需包含:
    routingName
    (唯一标签)、
    addressType
    (默认
    EmailToCase
    ,或
    Outlook
    /
    GmailOAuth
    )、
    caseOrigin
    casePriority
    。如果缺少
    caseOrigin
    casePriority
    ,平台会拒绝该地址,因此需将这四个字段视为源文件中的必填项。
  • 每个路由地址对应的客户侧邮件地址——按地址顺序逐个明确询问用户;绝不猜测、默认或复用之前上下文的内容。该信息不会存储在源文件中——在应用时通过
    --routing-email
    传递(每个地址对应一个参数;若数量不匹配,脚本会终止运行)。
  • 支持设置——默认案例所有者与自动案例用户——优先保留现有设置,绝不假设:
    • 独立设置,按字段保留。每个已配置的字段都会保持不变;仅当用户要求时才更改(使用
      --overwrite-support-settings
      )。仅询问未设置的字段
    • 对于每个未设置的字段,需询问(绝不默认使用已认证用户):默认案例所有者类型
      User
      /
      Queue
      )+ (活跃用户名或队列开发者名称)→
      --owner-type
      /
      --owner-value
      ;自动案例用户类型
      User
      /
      System
      )——
      User
      需要用户名
      System
      无需值→
      --automated-type
      /
      --automated-value
      (+ 可选的
      --system-user-email
      ,当组织的自动用户尚未存在时用于System类型)。
    • 若任何值无效,脚本会运行失败——请获取有效值后重新运行;绝不替代或猜测。
    • 仅当用户明确要求时,才使用
      --use-authenticated-user
  • 每个地址的案例默认设置(可选)——
    createTask
    saveEmailHeaders
    ,以及可选的每个地址的默认案例所有者
    caseOwner
    +
    caseOwnerType
    ),按地址选择加入(请参阅步骤6):默认情况下会省略这些设置,因此案例会分配给组织默认案例所有者/分配规则。若设置这些字段,
    caseOwner
    (活跃用户名或队列开发者名称)必须与
    caseOwnerType
    User
    /
    Queue
    )配对;脚本会针对组织验证该值,若不存在则终止运行。
  • 组织层面开关(可选)——仅当用户要求时才设置。分为两个容器:
    emailToCase
    部分
    enableHtmlEmail
    notifyOwnerOnNewCaseEmail
    enableE2CDeduplicateAttachments
    showWordCountInComposer
    ,以及
    enableE2CSourceTracking
    overEmailLimitAction
    unauthorizedSenderAction
    ),以及顶层支持设置
    enableDraftEmails
    ——复数元素名称,是
    emailToCase
    的同级元素)。请参阅步骤4的表格了解容器/UI标签映射;顶层标量开关会在阶段A中应用。
默认值:
enableEmailToCase
enableOnDemandEmailToCase
默认设为
true
(两者均为必填项——必须先启用On-Demand才能创建路由地址);
addressType
默认设为
EmailToCase
。支持设置无默认值——若已配置则保留,否则需询问用户(绝不使用已认证用户)。

Workflow

工作流

All steps are sequential.
  1. Confirm the org (and its type) — confirm the target org alias is authenticated (
    sf org display --target-org <alias>
    ). The apply script checks the
    Organization
    row and refuses to mutate a production org (non-sandbox, non-trial) unless
    --confirm-production
    is passed — enabling Email-to-Case is permanent and org-wide. If production, tell the user and confirm before re-running with
    --confirm-production
    . Sandboxes, scratch orgs, and trials deploy without the flag.
  2. Elicit the routing email(s) — ask the user for the exact customer-facing email address for each routing address (never assume, default, or carry a value over from earlier). Pass them to the script via
    --routing-email
    in the order the addresses appear in the source file.
  3. Load the template — read
    assets/CaseSettings.settings-meta.xml
    for structure and field placement. Its comments are authoring guidance for you — never copy them into the output. Emit only the elements you set; the output must be comment-free, matching
    examples/CaseSettings-two-addresses.settings-meta.xml
    .
  4. Enable the E2C switches, then confirm the optional toggles — set both
    enableEmailToCase
    and
    enableOnDemandEmailToCase
    to
    true
    (both required; On-Demand must be on before routing addresses can be created — the script enables it in Phase A before Phase B). Then handle the non-required convenience settings, which the template turns on by default:
    UI labelFieldContainer
    Enable HTML email
    enableHtmlEmail
    emailToCase
    Eliminate duplicate email attachments
    enableE2CDeduplicateAttachments
    emailToCase
    Show word count in composer
    showWordCountInComposer
    emailToCase
    Notify case owners on new emails
    notifyOwnerOnNewCaseEmail
    emailToCase
    Enable Email Drafts
    enableDraftEmails
    (top-level
    CaseSettings
    )
    Support Settings
    Before enabling these, tell the user exactly which will be turned on and let them opt out (e.g. "I'll also enable these optional settings: … — let me know if you'd like to skip any."). Remove any the user opts out of; keep the rest in their correct container (four inside
    <emailToCase>
    ,
    enableDraftEmails
    at the root). Never silently enable these or any other optional flag the user didn't agree to. Confirmed toggles apply in Phase A.
  5. Pick the correct surface per routing address — for each address, decide by
    addressType
    using
    references/routing_address_reference.md
    . If any requested address is
    E2cEasy
    , stop and route the user to the Service Easy Setup wizard instead of emitting Metadata for it.
  6. Populate routing-address fields — for each
    EmailToCase
    /
    Outlook
    /
    GmailOAuth
    address, set
    addressType
    ,
    routingName
    ,
    caseOrigin
    , and
    casePriority
    (all required — the platform rejects the operation with "Missing caseOrigin"/"Missing casePriority" if either is absent), plus any optional case defaults. Do not put
    emailAddress
    in the source file — it is supplied at apply time via
    --routing-email
    . Do not set the read-only fields
    emailServicesAddress
    or
    isVerified
    — the platform manages them. See
    examples/CaseSettings-two-addresses.settings-meta.xml
    for a complete multi-address example.
    Per-address Default Case Owner (opt-in). Ask one address at a time whether cases from this address go to a specific owner or fall to the org Default Case Owner / assignment rules (the default) — different addresses can route to different owners. If the user declines, leave
    caseOwner
    /
    caseOwnerType
    out of the source file entirely (the template ships them commented out). If the user opts in, ask for the type (
    User
    /
    Queue
    ) and value (active Username or Queue DeveloperName) and set both
    <caseOwnerType>
    and
    <caseOwner>
    — the platform rejects
    caseOwner
    without its type.
    apply-casesettings.py
    validates it against the org and fails closed if absent. Do not guess or reuse the top-level Default Case Owner.
  7. Determine Support Settings (Default Case Owner + Automated Case User) — run
    python3 scripts/apply-casesettings.py --target-org <alias> --input <source-file> --verify-only
    and inspect
    defaultCaseOwner
    /
    defaultCaseUser
    /
    useSystemUserAsDefaultCaseUser
    . When the user names a value, write it into the source file (
    defaultCaseOwner
    +
    defaultCaseOwnerType
    ;
    defaultCaseUser
    , or
    useSystemUserAsDefaultCaseUser
    + optional
    systemUserEmail
    ) — the scored, versionable artifact; the script also accepts these as flags. Leave each field the org already has as-is — omit it and it is preserved (override only if the user asks — then
    --overwrite-support-settings
    ). For a field unset and unnamed, ask; never assume the authenticated user (
    --use-authenticated-user
    only if explicitly asked).
  8. Validate the source file — run
    python3 scripts/validate-casesettings.py <path-to-source-file>
    and resolve any reported errors before applying.
  9. Apply to the org — run:
    bash
    python3 scripts/apply-casesettings.py --target-org <alias> --input <source-file> \
        --routing-email <email-for-address-1> [--routing-email <email-for-address-2> ...] \
        [--owner-type User|Queue --owner-value <username-or-queue-devname>] \
        [--automated-type User --automated-value <username> | --automated-type System [--system-user-email <email>]] \
        [--confirm-production]
    Provide exactly one
    --routing-email
    per routing address, in document order. Supply the owner/automated flags only when the org's Support Settings are not already configured (step 7); if configured, omit them and they are preserved. If the script rejects a value as invalid, relay it, get a valid value, and re-run — never fall back to the authenticated user. If the script reports production and exits, do not add
    --confirm-production
    yourself
    — confirm with the user first (step 1). The script applies Phase A (support settings + toggles), then Phase B (routing addresses), re-reads to verify, and exits non-zero on any fault.
  10. Confirm the result — check the JSON summary:
    verified.enableEmailToCase
    /
    verified.enableOnDemandEmailToCase
    are
    true
    ,
    verified.routingAddressCount
    matches the address count, each
    phaseB
    entry is
    status: created
    (or
    already_exists
    ), and
    supportSettings.action
    is
    preserved-existing
    /
    set-from-input
    /
    set-from-authenticated-user
    . Use
    --verify-only
    to re-read without writing.
Configuration is complete after step 10.

所有步骤均按顺序执行。
  1. 确认组织(及其类型)——确认目标组织别名已完成认证(
    sf org display --target-org <alias>
    )。应用脚本会检查
    Organization
    行,并且拒绝修改生产组织(非沙盒、非试用组织),除非传入
    --confirm-production
    参数——启用Email-to-Case是永久性的且面向整个组织。若为生产组织,请告知用户并确认后,再添加
    --confirm-production
    参数重新运行。沙盒、临时组织和试用组织无需该标记即可部署。
  2. 获取路由邮箱——向用户询问每个路由地址对应的准确客户侧邮件地址(绝不假设、默认或复用之前的值)。按源文件中地址的顺序,通过
    --routing-email
    参数传递给脚本。
  3. 加载模板——读取
    assets/CaseSettings.settings-meta.xml
    获取结构和字段位置。其中的注释是为提供的创作指导——请勿将其复制到输出文件中。仅输出你设置的元素;输出文件必须无注释,与
    examples/CaseSettings-two-addresses.settings-meta.xml
    保持一致。
  4. 启用E2C开关,然后确认可选设置——将
    enableEmailToCase
    enableOnDemandEmailToCase
    均设为
    true
    (两者均为必填项;必须先启用On-Demand才能创建路由地址——脚本会在阶段A中启用该设置,然后执行阶段B)。然后处理非必填的便捷设置,这些设置默认会在模板中启用:
    UI标签字段容器
    启用HTML邮件
    enableHtmlEmail
    emailToCase
    消除重复邮件附件
    enableE2CDeduplicateAttachments
    emailToCase
    在编辑器中显示字数统计
    showWordCountInComposer
    emailToCase
    新邮件到达时通知案例所有者
    notifyOwnerOnNewCaseEmail
    emailToCase
    启用邮件草稿
    enableDraftEmails
    (顶层
    CaseSettings
    支持设置
    在启用这些设置前,需明确告知用户将开启哪些设置,并让用户选择是否退出(例如:“我还将启用以下可选设置:……——如果你想跳过任何设置,请告知我。”)。移除用户选择退出的设置;保留其余设置并放入正确的容器中(四个放入
    <emailToCase>
    内,
    enableDraftEmails
    放在根层级)。绝不在用户未同意的情况下静默启用这些或任何其他可选标记。已确认的开关会在阶段A中应用。
  5. 为每个路由地址选择正确的类型——对于每个地址,根据
    addressType
    参考
    references/routing_address_reference.md
    进行选择。若任何请求的地址为
    E2cEasy
    类型,请停止操作并引导用户使用Service Easy Setup向导,而非生成元数据。
  6. 填充路由地址字段——对于每个
    EmailToCase
    /
    Outlook
    /
    GmailOAuth
    地址,设置
    addressType
    routingName
    caseOrigin
    casePriority
    (均为必填项——若缺少其中任何一项,平台会返回“Missing caseOrigin”/“Missing casePriority”并拒绝操作),以及任何可选的案例默认设置。请勿在源文件中添加
    emailAddress
    ——该信息会在应用时通过
    --routing-email
    参数传递。请勿设置只读字段
    emailServicesAddress
    isVerified
    ——这些由平台管理。请参阅
    examples/CaseSettings-two-addresses.settings-meta.xml
    获取完整的多地址示例。
    每个地址的默认案例所有者(选择加入)。逐个询问用户,来自地址的案例是要分配给特定所有者,还是默认分配给组织默认案例所有者/分配规则(默认选项)——不同的地址可以路由到不同的所有者。若用户拒绝,请从源文件中完全移除
    caseOwner
    /
    caseOwnerType
    (模板中这些字段是注释状态)。若用户选择加入,请询问类型
    User
    /
    Queue
    )和(活跃用户名或队列开发者名称),并同时设置
    <caseOwnerType>
    <caseOwner>
    ——若仅设置
    caseOwner
    而未设置类型,平台会拒绝该操作。
    apply-casesettings.py
    会针对组织验证该值,若不存在则终止运行。请勿猜测或复用顶层默认案例所有者的值。
  7. 确定支持设置(默认案例所有者 + 自动案例用户)——运行
    python3 scripts/apply-casesettings.py --target-org <alias> --input <source-file> --verify-only
    ,并检查
    defaultCaseOwner
    /
    defaultCaseUser
    /
    useSystemUserAsDefaultCaseUser
    当用户指定值时,将其写入源文件
    defaultCaseOwner
    +
    defaultCaseOwnerType
    defaultCaseUser
    ,或
    useSystemUserAsDefaultCaseUser
    + 可选的
    systemUserEmail
    )——这是可评分、可版本化的工件;脚本也接受这些参数作为标记。保留组织已有的每个字段——若省略该字段,则会保留现有值(仅当用户要求时才覆盖——需使用
    --overwrite-support-settings
    )。对于未设置且用户未指定的字段,请询问用户;绝不假设使用已认证用户(仅当明确要求时才使用
    --use-authenticated-user
    )。
  8. 验证源文件——运行
    python3 scripts/validate-casesettings.py <path-to-source-file>
    ,并在应用前解决所有报告的错误。
  9. 应用到组织——运行:
    bash
    python3 scripts/apply-casesettings.py --target-org <alias> --input <source-file> \
        --routing-email <email-for-address-1> [--routing-email <email-for-address-2> ...] \
        [--owner-type User|Queue --owner-value <username-or-queue-devname>] \
        [--automated-type User --automated-value <username> | --automated-type System [--system-user-email <email>]] \
        [--confirm-production]
    为每个路由地址提供一个
    --routing-email
    参数,顺序需与源文件中的地址顺序一致。仅当组织的支持设置尚未配置时(步骤7),才提供所有者/自动用户标记;若已配置,请省略这些标记,现有值会被保留。若脚本拒绝某个值为无效值,请告知用户,获取有效值后重新运行——绝不回退到已认证用户。若脚本报告为生产组织并退出,请不要自行添加
    --confirm-production
    参数
    ——需先与用户确认(步骤1)。脚本会先应用阶段A(支持设置+开关),然后应用阶段B(路由地址),重新读取进行验证,若出现任何错误则返回非零退出码。
  10. 确认结果——检查JSON摘要:
    verified.enableEmailToCase
    /
    verified.enableOnDemandEmailToCase
    true
    verified.routingAddressCount
    与地址数量匹配,每个
    phaseB
    条目的
    status
    created
    (或
    already_exists
    ),且
    supportSettings.action
    preserved-existing
    /
    set-from-input
    /
    set-from-authenticated-user
    。可使用
    --verify-only
    参数重新读取配置而不进行写入操作。
完成步骤10后,配置即完成。

After setup — post-completion guidance

设置完成后——后续指导

The items below are not workflow steps — present them to the user once setup is confirmed.
以下内容不属于工作流步骤——在确认设置完成后告知用户。

Forwarding (required for real inbound mail)

转发(接收实际入站邮件所需)

Always give the user this guidance — it is how inbound mail to the customer-facing address actually reaches Salesforce:
Your routing address now has a Salesforce-generated email services address. To receive inbound mail, configure your email system to forward mail sent to your customer-facing address (e.g.
support@company.com
) to that generated services address.
请务必向用户提供以下指导——这是确保发送到客户侧地址的入站邮件能够到达Salesforce的方式:
你的路由地址现在拥有一个由Salesforce生成的邮件服务地址。要接收入站邮件,请配置你的邮件系统,将发送到客户侧地址(例如
support@company.com
)的邮件转发到该生成的服务地址。

End-to-end proof (Act 3)

端到端验证(第三阶段)

Offer to prove inbound email creates Cases — a live round-trip; skip it if the user declines. The skill never sends email — it orchestrates two human actions, then verifies with SOQL: (1) Address ownership — Salesforce emails a confirmation link;
isVerified
flips only when the human clicks it. Tell the user to click it and wait. (2) Send a test email — ask the user to send one real email from an external mailbox to the routing address's Salesforce-generated email services address (not the customer-facing address, which only receives mail once forwarding is configured), report the sender, and wait. (3) Verify with evidence — then run:
bash
python3 scripts/apply-casesettings.py --target-org <alias> --verify-cases \
    [--supplied-email <external-sender-address>]
Read-only: it queries
Case
where
Origin='Email'
(last 3 days, optionally narrowed by sender) plus the linked incoming
EmailMessage
rows (
Incoming=true
,
ParentId
= the new Case), and exits non-zero if no matching Case has a linked incoming email (mail not processed yet — wait and re-run — or address not verified). On success it prints the
Case
+
EmailMessage
evidence with
proven: true
.

主动向用户提供入站邮件创建案例的验证服务——一次完整的往返测试;若用户拒绝则跳过。本技能绝不会发送邮件——它会协调两个人工操作,然后通过SOQL进行验证:(1) 地址所有权——Salesforce会发送确认链接;仅当用户点击链接后,
isVerified
才会变为已验证状态。请告知用户点击链接并等待。(2) 发送测试邮件——请用户从外部邮箱向路由地址的Salesforce生成邮件服务地址(而非客户侧地址,客户侧地址仅在配置转发后才会接收邮件)发送一封真实邮件,报告发件人信息并等待。(3) 验证并提供证据——然后运行:
bash
python3 scripts/apply-casesettings.py --target-org <alias> --verify-cases \
    [--supplied-email <external-sender-address>]
该操作仅为只读:它会查询
Case
Origin='Email'
的记录(最近3天,可选按发件人筛选),以及关联的入站
EmailMessage
记录(
Incoming=true
ParentId
= 新案例),若未找到匹配且关联入站邮件的案例,则返回非零退出码(邮件尚未处理——请等待后重新运行——或地址未验证)。验证成功后,会打印
Case
+
EmailMessage
的证据,并显示
proven: true

Rules / Constraints

规则/约束

ConstraintRationale
Apply via
apply-casesettings.py
(two-phase
updateMetadata
), never a plain deploy or a minimal
emailToCase
patch
A single deploy fails on a fresh org; the full
emailToCase
block (not a field-level flip) is what provisions On-Demand before addresses bind. See
references/apply-mechanics.md
.
Write only the top-level fields the skill owns; never echo the whole
CaseSettings
record
The platform re-validates every top-level field in the payload (e.g. Case Feed → Chatter); sending only
emailToCase
+
enableDraftEmails
+ Support Settings avoids unrelated failures and needs no Chatter prerequisite. Omitted fields keep their values via field-level merge.
The customer-facing email must be explicit user input (
--routing-email
), never in the source file and never assumed
Prevents a guessed or stale address from being provisioned. The script fails closed if
--routing-email
count ≠ address count.
CaseSettings
fullName
is always
Case
It is an org singleton settings type; the script targets
Case
automatically.
Support Settings are preserved per field if configured; never assumed if notDefault Case Owner and Automated Case User are independent — each configured field is left untouched (unless
--overwrite-support-settings
), and only an unset field requires an explicit, org-validated value (fails closed otherwise). The authenticated user is used only with
--use-authenticated-user
.
Automated Case User "System" and a named
defaultCaseUser
are mutually exclusive
--automated-type System
sets
useSystemUserAsDefaultCaseUser
and must not carry a user value; the platform rejects both.
The script reads → patches → updates (append-only for addresses)It merges onto current settings, so existing routing addresses are preserved; a duplicate
routingName
/
emailAddress
is reported as
already_exists
. New addresses are emitted before existing ones (
updateMetadata
replaces the collection wholesale and would drop an existing address that a new one follows; a runtime guard fails the run if any existing address is dropped). See
references/apply-mechanics.md
.
EmailToCaseSettings
is never applied directly;
enableEmailToCase
cannot be turned off once on
It is written only as the
emailToCase
child of
CaseSettings
. The platform permanently enables the feature after the first
true
apply; never rely on setting it back to
false
.
Production orgs require explicit
--confirm-production
; never add the flag unprompted
Enabling Email-to-Case is permanent and org-wide. The script fails closed on a non-sandbox, non-trial org (and one whose type it can't read) until the user confirms. Sandboxes and trials are exempt.
Proving inbound Cases is a read-only step the user triggers; the skill never sends email
--verify-cases
only queries
Case
/
EmailMessage
after the human verified the address and sent a test email. Fails closed until a Case with a linked incoming email exists.
E2cEasy
addresses must use the Service Easy Setup wizard
The prebuilt
service_case
queue binding and
isVerified
flip are not reproducible through the Metadata API.
Never write
emailServicesAddress
or
isVerified
Both are read-only, platform-generated; the script strips them if present.
The generated source file contains only the elements being set — no XML commentsTemplate/example comments are authoring guidance, not output. Copying them bloats the file (gold is comment-free) and CLI-example comments with
<placeholder>
tokens can fail XML validation. Put explanation in your chat reply, never in the
.settings-meta.xml
.

约束原因
通过
apply-casesettings.py
(分两阶段的
updateMetadata
)应用配置,绝不使用普通部署或最小化
emailToCase
补丁
在全新组织中单次部署会失败;完整的
emailToCase
块(而非字段级修改)是在绑定地址前启用On-Demand的必要条件。请参阅
references/apply-mechanics.md
仅写入本技能负责的顶层字段;绝不返回完整的
CaseSettings
记录
平台会重新验证请求中的每个顶层字段(例如Case Feed → Chatter);仅发送
emailToCase
+
enableDraftEmails
+ 支持设置可避免无关错误,且无需Chatter前置条件。省略的字段会通过字段级合并保留其值。
客户侧邮件地址必须是用户明确输入的内容(
--routing-email
),绝不在源文件中存储或假设
防止配置猜测或过期的地址。若
--routing-email
数量与地址数量不匹配,脚本会终止运行。
CaseSettings
fullName
始终为
Case
这是组织级单例设置类型;脚本会自动定位到
Case
若支持设置已配置,则按字段保留;若未配置则绝不假设默认案例所有者和自动案例用户是独立的——每个已配置的字段都会保持不变(除非使用
--overwrite-support-settings
),仅未设置的字段需要明确的、经过组织验证的值(否则终止运行)。仅当使用
--use-authenticated-user
时才会使用已认证用户。
自动案例用户的“System”类型和指定的
defaultCaseUser
互斥
--automated-type System
会设置
useSystemUserAsDefaultCaseUser
,且不能携带用户值;平台会拒绝同时设置两者。
脚本会读取→补丁→更新(地址仅追加)它会合并到当前设置中,因此现有路由地址会被保留;若
routingName
/
emailAddress
重复,会报告为
already_exists
。新地址会被添加到现有地址之前
updateMetadata
会完全替换集合,若新地址在现有地址之后,会导致现有地址丢失;运行时防护会在检测到现有地址丢失时终止运行)。请参阅
references/apply-mechanics.md
绝不直接应用
EmailToCaseSettings
enableEmailToCase
启用后无法关闭
仅能作为
CaseSettings
emailToCase
子元素进行配置。平台在首次设置为
true
后会永久启用该功能;绝不依赖将其设回
false
的操作。
生产组织需要明确的
--confirm-production
参数;绝不自行添加该标记
启用Email-to-Case是永久性的且面向整个组织。脚本会在非沙盒、非试用组织(以及无法读取类型的组织)上终止运行,直到用户确认。沙盒和试用组织无需该标记。
验证入站案例是用户触发的只读步骤;本技能绝不会发送邮件
--verify-cases
仅会在用户验证地址并发送测试邮件后查询
Case
/
EmailMessage
。直到存在关联入站邮件的案例时才会成功,否则终止运行。
E2cEasy
地址必须使用Service Easy Setup向导
预构建的
service_case
队列绑定和
isVerified
状态切换无法通过Metadata API实现。
绝不写入
emailServicesAddress
isVerified
两者均为只读字段,由平台生成;若存在这些字段,脚本会将其移除。
生成的源文件仅包含正在设置的元素——无XML注释模板/示例中的注释是创作指导,而非输出内容。复制注释会增大文件体积(最优文件是无注释的),且包含
<placeholder>
标记的CLI示例注释可能会导致XML验证失败。请在聊天回复中进行解释,绝不要放入
.settings-meta.xml
文件中。

Gotchas

常见问题

For the full symptom → resolution table (Phase B provisioning errors, Case Feed/Chatter, per-address owner half-fills,
GmailOAuth
conflicts,
--verify-cases
failures, and every toggle-placement pitfall), read
references/troubleshooting.md
.

如需完整的症状→解决方案表格(阶段B配置错误、Case Feed/Chatter问题、每个地址所有者的半填充问题、
GmailOAuth
冲突、
--verify-cases
失败以及所有开关放置陷阱),请阅读
references/troubleshooting.md

Output Expectations

输出预期

Deliverables:
  • A
    CaseSettings
    source file (e.g.
    Case.settings-meta.xml
    ) for the desired
    emailToCase
    state — toggles and routing-address fields, without
    emailAddress
    (supplied at apply time), read-only fields, or XML comments. Structure follows
    assets/CaseSettings.settings-meta.xml
    .
  • The applied org state from
    apply-casesettings.py
    , plus its JSON summary (resolved owner, per-address status, verification read).

交付物:
  • 对应所需
    emailToCase
    状态的
    CaseSettings
    源文件(例如
    Case.settings-meta.xml
    )——包含开关和路由地址字段,不包含
    emailAddress
    (应用时传递)、只读字段或XML注释。结构遵循
    assets/CaseSettings.settings-meta.xml
  • apply-casesettings.py
    返回的已应用组织状态,以及其JSON摘要(已解析的所有者、每个地址的状态、验证读取结果)。

Reference File Index

参考文件索引

FileWhen to read / run
assets/CaseSettings.settings-meta.xml
Step 3 — the starting template for the source file
references/apply-mechanics.md
Read before touching how the script builds or sequences its
updateMetadata
payloads
references/troubleshooting.md
When the apply or verify step reports an error, or a configured setting doesn't behave — full symptom → resolution table
references/routing_address_reference.md
Steps 5–6 — routing-address field semantics and the
addressType
surface-selection rule
examples/CaseSettings-two-addresses.settings-meta.xml
Step 6 — to verify the source-file structure for multiple routing addresses
scripts/check-agent-email-capability.sh
Attaching an Agentforce service agent — the pre-delegation capability gate (probes for
BotEmailDefinition
)
scripts/validate-casesettings.py
Step 8 — deterministic structural validation before applying
scripts/apply-casesettings.py
Step 9 — applies the settings via two-phase
updateMetadata
and verifies
scripts/tests/test_get_session.py
Run when changing session-token acquisition (
get_session
/
_usable_access_token
) — the unit suite guarding token extraction and API-version resolution
文件读取/运行时机
assets/CaseSettings.settings-meta.xml
步骤3——源文件的起始模板
references/apply-mechanics.md
在修改脚本构建或排序
updateMetadata
请求的方式前阅读
references/troubleshooting.md
当应用或验证步骤报告错误,或配置的设置未按预期运行时阅读——完整的症状→解决方案表格
references/routing_address_reference.md
步骤5–6——路由地址字段语义和
addressType
类型选择规则
examples/CaseSettings-two-addresses.settings-meta.xml
步骤6——验证多路由地址的源文件结构
scripts/check-agent-email-capability.sh
绑定Agentforce服务代理时——委托前的能力检测(探测
BotEmailDefinition
scripts/validate-casesettings.py
步骤8——应用前的确定性结构验证
scripts/apply-casesettings.py
步骤9——通过分两阶段的
updateMetadata
应用设置并验证
scripts/tests/test_get_session.py
当修改会话令牌获取方式(
get_session
/
_usable_access_token
)时运行——用于保护令牌提取和API版本解析的单元测试套件