customware-email

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Customer Email

客户邮件

<purpose>
Implement one coherent Customware email capability for a Customware-generated app. The capability receives customer replies through the provisioned Postmark inbound webhook and sends customer-facing messages through the same development Postmark server's HTTPS API.
The task provides the project-specific addresses. The two managed server ENV values provide the credentials. This skill provides the implementation method, durable behavior, and verification contract.
</purpose>
Build toward the existing app. Reuse its Hono routes, Drizzle schema, SQLite database, logging, error, and
Result
patterns. A small, native integration is easier to reason about and safer than a second email framework.

<purpose>
为Customware生成的应用实现一套连贯的Customware邮件功能。该功能通过预配置的Postmark入站webhook接收客户回复,并通过同一开发环境Postmark服务器的HTTPS API发送面向客户的消息。
任务会提供项目专属地址。两个受管理的服务器环境变量提供凭证。本技能提供实现方法、持久化行为和验证约定。
</purpose>
基于现有应用构建。复用其Hono路由、Drizzle schema、SQLite数据库、日志、错误处理和
Result
模式。原生轻量集成比引入第二个邮件框架更易理解且更安全。

Read first

必读内容

Read these references before editing source files:
  1. references/common-architecture.md — task inputs, platform boundaries, credentials, stack, and shared integration shape.
  2. references/inbound.md — the fixed webhook, authentication, durable receipt, deduplication, and recovery contract.
  3. references/outbound.md — direct Postmark API sending, message shape, sender/reply routing, and failure handling.
  4. references/common-quality.md — validation, safe logging, migration, tests, and final verification.
Read the inbound and outbound references even when the task initially sounds one-sided. Replies make the two directions one feature: inbound mail must be able to reach the app, and outbound mail must route replies back to the same virtual address.
<read_order>
Before implementation, also read the target repository's
AGENTS.md
, the complete Builder task, relevant project docs, and the existing database/route/service contracts. Treat the target repository as authoritative when a framework detail differs from an example here.
</read_order>
在编辑源文件前,请阅读以下参考文档:
  1. references/common-architecture.md — 任务输入、平台边界、凭证、技术栈和共享集成架构。
  2. references/inbound.md — 固定webhook、认证、持久化收件、去重和恢复约定。
  3. references/outbound.md — 直接调用Postmark API发送邮件、消息格式、发件人/回复路由和故障处理。
  4. references/common-quality.md — 验证、安全日志、迁移、测试和最终验证。
即使任务最初看似只涉及单向功能,也要阅读入站和出站参考文档。回复功能让双向邮件成为一个整体:入站邮件必须能抵达应用,出站邮件必须将回复路由回同一个虚拟地址。
<read_order>
在实现前,还需阅读目标仓库的
AGENTS.md
、完整的Builder任务、相关项目文档以及现有数据库/路由/服务约定。当框架细节与本文示例存在差异时,以目标仓库的内容为准。
</read_order>

Fixed platform contract

固定平台约定

ConcernRequired decision
Postmark serverUse the one development server already provisioned for this project. The app does not create, delete, or configure it.
Inbound route
POST /api/email/inbound
Inbound authenticationHTTP Basic Auth, username
customware
, password from
POSTMARK_INBOUND_WEBHOOK_SECRET
Server credentialsRead
POSTMARK_INBOUND_WEBHOOK_SECRET
and
POSTMARK_SERVER_TOKEN
only on the server.
Inbound addressUse the exact virtual address supplied in the task. Do not create an ENV for it.
Outbound senderUse the exact task-provided sender, currently
messages@customware.ai
. Do not create an ENV for it.
Outbound streamPostmark's existing Default Transactional stream (
outbound
).
TransportDirect HTTPS requests to Postmark's Email API from server code.
SMTPDo not enable or use SMTP.
Customware gatewayDo not add a Customware send endpoint, proxy, or email gateway.
ProductionImplement the development capability described by the task. Do not add production-server, publish, or environment-branching behavior.
<address_source_of_truth>
The task description is the source of truth for the virtual inbound address and outbound From address. Keep each value in one server-owned constant/module so it cannot drift between the sender, reply routing, and reviewer-visible code. Never replace either value with a placeholder, a guessed address, or a new ENV.
</address_source_of_truth>
关注点必填决策
Postmark服务器使用已为该项目预配置的开发服务器。应用不得创建、删除或配置该服务器。
入站路由
POST /api/email/inbound
入站认证HTTP Basic Auth,用户名
customware
,密码来自
POSTMARK_INBOUND_WEBHOOK_SECRET
服务器凭证仅在服务器端读取
POSTMARK_INBOUND_WEBHOOK_SECRET
POSTMARK_SERVER_TOKEN
入站地址使用任务中提供的精确虚拟地址。请勿为其创建环境变量。
出站发件人使用任务提供的精确发件人地址,当前为
messages@customware.ai
。请勿为其创建环境变量。
出站流Postmark现有的默认事务流(
outbound
)。
传输方式从服务器代码直接向Postmark的Email API发送HTTPS请求。
SMTP请勿启用或使用SMTP。
Customware网关请勿添加Customware发送端点、代理或邮件网关。
生产环境实现任务描述的开发环境功能。请勿添加生产服务器、发布或环境分支相关行为。
<address_source_of_truth>
任务描述是虚拟入站地址和出站发件人地址的唯一可信来源。将每个地址保存在一个服务器专属的常量/模块中,避免发件人、回复路由和评审可见代码之间的地址不一致。切勿用占位符、猜测地址或新环境变量替换任一地址。
</address_source_of_truth>

Non-negotiables

不可协商规则

  • Keep both Postmark credentials server-only. Never place them in browser code,
    VITE_*
    , HTML, JSON responses, task output, logs, or client state.
  • Treat
    .env
    and
    .env.*
    as inaccessible. Do not inspect them with file commands. A runtime check may use
    node --env-file=.env ...
    without printing environment values.
  • Register the inbound route before static serving and the SPA fallback.
  • Persist an inbound delivery before acknowledging it. The 200 response means the raw delivery is safe to recover, not that application processing finished.
  • Enforce
    MessageID
    uniqueness in the database. Do not implement deduplication as read-then-insert.
  • Make inbound processing recoverable after a crash or restart; an in-memory callback cannot be the only record of work.
  • Return the contract statuses in the inbound reference. Never return
    403
    to Postmark for this receiver.
  • Send outbound mail only from server code with
    X-Postmark-Server-Token
    and
    MessageStream: "outbound"
    .
  • Use the task's virtual inbound address as
    ReplyTo
    , so a customer reply comes back through the existing webhook.
  • Keep message content and credentials out of logs. Log only safe operational identifiers and error categories.
  • Reuse existing contracts and error/result conventions. Avoid duplicate validation, speculative abstractions, compatibility branches, or a second persistence framework.
  • 确保两个Postmark凭证仅在服务器端使用。绝不能将其放入浏览器代码、
    VITE_*
    变量、HTML、JSON响应、任务输出、日志或客户端状态中。
  • .env
    .env.*
    为不可访问文件。请勿用文件命令查看其内容。运行时检查可使用
    node --env-file=.env ...
    但不得打印环境变量值。
  • 在静态服务和SPA回退之前注册入站路由。
  • 在确认收件前先持久化入站邮件。返回200响应仅表示原始邮件已安全保存,不代表应用处理已完成。
  • 在数据库中强制
    MessageID
    唯一性。请勿将去重实现为先读取再插入的逻辑。
  • 确保入站处理在崩溃或重启后可恢复;内存回调不能作为工作记录的唯一方式。
  • 入站请求返回参考文档中约定的状态码。绝不能向Postmark的该接收器返回
    403
  • 仅从服务器代码发送出站邮件,且需携带
    X-Postmark-Server-Token
    MessageStream: "outbound"
  • 将任务提供的虚拟入站地址设为
    ReplyTo
    ,确保客户回复能通过现有webhook返回。
  • 请勿在日志中记录消息内容和凭证。仅记录安全的操作标识符和错误类别。
  • 复用现有约定和错误/结果处理规范。避免重复验证、推测性抽象、兼容性分支或引入第二个持久化框架。

Implementation workflow

实现流程

1. Establish the task contract

1. 确认任务约定

  1. Read the task completely.
  2. Extract the exact virtual inbound address and outbound From address.
  3. Confirm the task names
    customware-email
    and that the Postmark server has already been provisioned.
  4. Stop with a clear
    action_required
    result if either address or either managed credential contract is unavailable. Do not invent values.
  1. 完整阅读任务内容。
  2. 提取精确的虚拟入站地址和出站发件人地址。
  3. 确认任务指定了
    customware-email
    技能,且Postmark服务器已预配置完成。
  4. 如果任一地址或任一受管理凭证约定不可用,立即返回明确的
    action_required
    结果。请勿自行编造值。

2. Inspect the generated app

2. 检查生成的应用

Locate the Hono entrypoint, route registration order, static/fallback handlers, Drizzle schema and migrations, query/service conventions, environment helper, logging boundary, and existing
Result
/Zod patterns. Identify where the app's customer workflows should consume an accepted email and where its existing business actions produce outbound messages.
定位Hono入口点、路由注册顺序、静态/回退处理器、Drizzle schema和迁移脚本、查询/服务规范、环境变量助手、日志边界以及现有的
Result
/Zod模式。确定应用的客户工作流应在何处处理已接收的邮件,以及现有业务操作应在何处生成出站消息。

3. Build the shared server foundation

3. 构建共享服务器基础

Create one small server-owned email configuration module for the task-provided addresses and the two managed ENV reads. Keep provider calls behind a focused Postmark client/adapter that follows the app's existing result and error patterns. Do not let browser requests choose the server token, From address, ReplyTo address, stream, or Postmark URL.
创建一个小型的服务器专属邮件配置模块,用于存储任务提供的地址和两个受管理环境变量的读取逻辑。将Postmark调用封装在一个符合应用现有结果和错误模式的专用Postmark客户端/适配器之后。禁止浏览器请求选择服务器令牌、发件人地址、回复地址、流或Postmark URL。

4. Implement inbound and outbound

4. 实现入站和出站功能

Follow references/inbound.md for the receiver and durable worker. Follow references/outbound.md for the Postmark Email API adapter and the app-facing send helper. Integrate both with existing domain flows instead of creating a parallel email subsystem.
遵循references/inbound.md实现接收器和持久化处理逻辑。遵循references/outbound.md实现Postmark Email API适配器和面向应用的发送助手。将两者与现有业务流程集成,而非创建独立的邮件子系统。

5. Verify progressively

5. 逐步验证

Run focused contract checks while implementing, then the repository's normal format, lint, typecheck, build, unit, and interactive checks. Use the test matrix in references/common-quality.md. If an external send is requested, use only an explicitly approved safe recipient; otherwise prove the exact request with a stubbed Postmark client and route-level tests.
在实现过程中运行针对性的约定检查,然后执行仓库常规的格式检查、代码 lint、类型检查、构建、单元测试和交互式检查。使用references/common-quality.md中的测试矩阵。如果需要发送外部邮件,仅使用明确批准的安全收件人;否则通过Stubbed Postmark客户端和路由级测试验证请求的准确性。

6. Perform the final audit

6. 执行最终审计

Search the final diff for credential names, hardcoded secrets, SMTP usage,
POSTMARK_ACCOUNT_TOKEN
, production branches, direct browser-to-Postmark calls, raw email logging, and a second gateway. Confirm the task addresses are the only email values embedded in generated application code and that the database migration is included and applied through the app's normal command.
在最终代码差异中搜索凭证名称、硬编码密钥、SMTP使用、
POSTMARK_ACCOUNT_TOKEN
、生产环境分支、浏览器直接调用Postmark、原始邮件日志以及第二个网关的相关内容。确认任务提供的地址是生成的应用代码中唯一嵌入的邮件地址,且数据库迁移脚本已包含并通过应用的常规命令执行。

Completion checklist

完成检查清单

  • The task's exact inbound and outbound addresses are used in one server-owned configuration module.
  • POSTMARK_INBOUND_WEBHOOK_SECRET
    protects the inbound route and
    POSTMARK_SERVER_TOKEN
    authorizes outbound HTTPS calls.
  • The inbound route captures raw JSON, validates
    MessageID
    , persists before 200, deduplicates by a database constraint, and recovers pending/stale work.
  • Outbound requests use
    POST /email
    ,
    X-Postmark-Server-Token
    ,
    MessageStream: "outbound"
    , the task's From, and the task's inbound ReplyTo.
  • SMTP, raw email, account-level provisioning, production behavior, and a Customware send gateway are absent.
  • Sensitive values and message content are absent from browser bundles, responses, and logs.
  • Migrations, focused tests, repository checks, build, and relevant browser verification pass.
  • The final diff and reviewer requirements are read back before sign-off.
  • 任务提供的精确入站和出站地址已在一个服务器专属配置模块中使用。
  • POSTMARK_INBOUND_WEBHOOK_SECRET
    用于保护入站路由,
    POSTMARK_SERVER_TOKEN
    用于授权出站HTTPS调用。
  • 入站路由捕获原始JSON、验证
    MessageID
    、在返回200前持久化数据、通过数据库约束去重,并能恢复待处理/过期的任务。
  • 出站请求使用
    POST /email
    X-Postmark-Server-Token
    MessageStream: "outbound"
    、任务指定的发件人地址和任务指定的入站回复地址。
  • 未使用SMTP、原始邮件、账户级配置、生产环境行为和Customware发送网关。
  • 敏感值和消息内容未出现在浏览器包、响应和日志中。
  • 迁移脚本、针对性测试、仓库检查、构建和相关浏览器验证均已通过。
  • 已重新阅读最终代码差异和评审要求,再进行签核。

Boundaries

边界说明

Use this skill for the generated app's Customware email implementation. The Customware control plane owns Postmark server provisioning, encryption, hidden ENV materialization, webhook URL reconciliation on sandbox restart, cleanup, and publish protection. Do not duplicate those responsibilities in the generated app.
Use
customware-ai
for AI gateway or AI Elements work,
customware-support-widget
for the support widget, and
task-workflow
when the Builder task requires its full gated execution protocol. Those skills complement this one; they do not replace the email contracts here.
本技能用于为生成的应用实现Customware邮件功能。Customware控制平面负责Postmark服务器的配置、加密、隐藏环境变量的实例化、沙箱重启时的webhook URL协调、清理和发布保护。请勿在生成的应用中重复这些职责。
AI网关或AI元素相关工作请使用
customware-ai
技能,支持小部件相关工作请使用
customware-support-widget
技能,当Builder任务需要完整的 gated 执行协议时请使用
task-workflow
技能。这些技能可与本技能互补,但不能替代本文中的邮件约定。