---
date: 2026-04-23 18:00
slug: m4-mail-model-touchreach
title: M4 触达架构 — 虚拟信封邮件模型 + agent gateway 通知
status: active
tags: [m4, pricing, touchreach, architecture, mail, envelope]
---

# M4 触达架构 — 虚拟信封邮件模型 + agent gateway 通知

## 场景

M4 要解决的核心黑洞：xiangqin 当前 `xq query` 返回 profile + user_id，但用户**看到后没法真实触达**对方——链路断在"从看到到联系"。不解决触达，付费意愿为零。

## 选项

三层触达架构候选：

- **A) 暴露联系方式**：profile 里加微信号 / 邮箱字段，查到即可加好友
- **B) 平台内聊天**：xiangqin 自建消息系统，用户在 xq 里聊
- **C) 虚拟信封 + agent gateway 通知**（采纳）：xiangqin 做代理信箱，支持 push（对方 agent 通道）+ pull（对方主动查收）双模；匿名代理双方的 URL/token

## 选 C，因为

- **不破宪法**：手机号 / 真实联系方式不落明文；匿名代理不透露 gateway URL/token
- **agent-native**：复用 OpenClaw 已有的 `/hooks/agent` webhook 协议（`src/gateway/hooks.ts` 源码已验证），任何实现同协议的 agent 框架都能接入，不绑死 OpenClaw
- **不做聊天**：xiangqin 只存邮件 + 转发通知，不做对话 UI / 历史 / 群组，维持"不做聊天"宪法
- **双通道兜底**：用户没配 agent gateway 也能用（走主动查收 `xq inbox`），降低接入门槛

放弃 A：手机号明文违反隐私红线；放弃 B：工作量大 + 聊天运营陷阱（反垃圾 / 内容审核 / 举报仲裁）。

## 架构要点

### 1. 信箱 vs 通知分离

- **信箱（inbox）**：基础设施，注册即开，所有用户都有
- **通知（notify）**：可选上层，需要配 `agent_gateway_url + agent_hooks_token + notify_on_new_mail=true` 三个字段才触发
- 信一经投递永久在对方邮箱（30 天保留），即使通知失败 / 未开通知也不影响

### 2. 虚拟信封付费模型

| 规则 | 值 |
|---|---|
| 每日免费信封 | 3 个，0 点重置 |
| 超额信封单价 | ¥1/个 |
| 付费方式 | 微信 / 支付宝直付，不做点数系统 |
| 回复是否消耗信封 | **是**（一封信 = 一个信封，物理直觉一致） |
| 信封退款条件 | 投递失败时退（被拉黑 / 对方注销）；投递成功不退 |

不做的（砍掉）：
- ❌ 点数系统（过度复杂）
- ❌ 推荐位曝光付费（v0.2+ 再看）
- ❌ 会员订阅 / 身份分层（等池子起来再做）
- ❌ 搜索竞价（AI 时代 query 权在用户，竞价无意义）
- ❌ 送礼物分成（不做聊天，无 hook 点）

### 3. 发信无限制；通知去重防打扰

- A 发信不限条数（100 封也行），信封成本自然限流
- 通知推送走**去重规则**：

```
有新信到达 B →
  B 没开通知 → 不推
  B 开了通知 →
    B 当前无未读（这是唯一未读）→ 推
    B 有未读 + 距上次通知 < 12h → 不推（防打扰）
    B 有未读 + 距上次通知 ≥ 12h → 推（兜底提醒）
```

12h 兜底：一天最多 2 次通知，白天 + 晚上各一次，避免过度打扰。

### 4. 信件状态维度（发信方透明可见）

一封信有 5 个并行维度：

| 维度 | 可能值 |
|---|---|
| 投递 | `delivered` / `blocked_by_recipient` / `recipient_quota_full` / `recipient_not_found` |
| 通知 | `not_enabled` / `pushed` / `push_failed` / `suppressed_dup` |
| 阅读 | `unread` / `read` |
| 回应 | `no_reply` / `replied`（带 reply_to_message_id） |
| 处置 | `none` / `reported` / `deleted_by_recipient` |

### 5. 举报 + 拉黑（保留取证）

- `xq report <message_id> --reason <text>` 举报某条
- `xq block <user_id>` / `unblock` / `blocklist` 拉黑
- 被拉黑方后续发信被服务端拦截（信封退）
- 举报记录**永久留档**（不走 30 天清理），可人工取证
- 自动处置（禁发 / 封号）v0.2+ 再做

### 6. 架构中立（不绑 OpenClaw）

profile 字段命名**不含 openclaw** 字样：

```
agent_gateway_url          可选，协议 http(s)
agent_hooks_token          可选
notify_on_new_mail         bool，默认 false
```

任何实现了 `POST /hooks/agent` 协议（OpenClaw 标准）的 agent 框架都能接入。OpenClaw 之外如 Claude Agent SDK 自建 agent 只要实现同协议即可。

### 7. Profile 新增相亲相关字段

| 字段 | 类型 | 范围 | 可空 |
|---|---|---|---|
| `height` | 整数 cm | 140-220 | ✅ |
| `education` | 枚举 | `highschool` / `associate` / `bachelor` / `master` / `phd` / `other` | ✅ |

可空原因：不是所有人愿意公开；查询方可用 `education IN (bachelor,master)` / `height>=170` 定向。DSL 白名单同步扩展支持这两个字段。

### 8. CLI 命令蓝图

```bash
# 发信方（A）
xq dm send <user_id> "<body>"                        # 消耗信封
xq envelope                                          # 查当日剩余 + 付费余量
xq envelope buy --count <N>                          # 购买额外信封
xq sent [--limit N]                                  # 查我发出去的信 + 状态表
xq sent show <message_id>                            # 详情（完整状态）

# 收信方（B）
xq inbox [--limit N]                                 # 查收件箱（平铺，不折叠）
xq inbox show <message_id>                           # 展开单条
xq inbox reply <message_id> "<body>"                 # 回复（消耗信封）
xq inbox report <message_id> --reason <text>         # 举报
xq inbox delete <message_id>                         # 软删（服务端仍留 30 天）
xq block <user_id>
xq unblock <user_id>
xq blocklist

# 配置
xq profile set agent_gateway_url <url>               # 可选
xq profile set agent_hooks_token <token>             # 可选
xq profile set notify_on_new_mail on|off             # 可选
```

inbox 默认**平铺**，不折叠同发信人——因为读者是 agent，agent 能自己处理线程语义。

## 代价 / 放弃了

- **网络效应缺失**：MVP 不做会员分层 / 推荐算法 / 社交图谱——如果 M5+ 数据表明"付费仅来自发信方，被看方完全被动"，需要重做收费结构
- **无内容审核**：信件正文不过滤手机号 / 微信号（用户意图就是换联系方式），但保留 30 天正文日志用于追诉
- **依赖 OpenClaw 生态成熟度**：通知推送体验取决于用户配置的 channel plugin（WeChat 需社区插件、门槛高；Telegram/iMessage 低门槛）；xiangqin 不碰 plugin 层
- **MVP 不做受众定向**（target filter）：ADR 第 7 节 profile 加了身高 + 学历字段，查询方可在 `xq query` WHERE 里用，但发信方的"只让 X 条件的人收到"定向推迟
- **单价 ¥1 占位**：拍脑袋值，真付费样本 ≥10 后迭代；无定价理论支撑

## 实施顺序

1. DB schema：`messages` / `envelope_usage` / `reports` / `blocks` 四张表 + profile 加 agent_gateway_url / agent_hooks_token / notify_on_new_mail / height / education 字段
2. 服务端核心：发信 / 投递 / 通知去重（12h 窗口）/ 举报 / 拉黑
3. CLI：`xq dm` / `xq inbox` / `xq envelope` / `xq report` / `xq block` 系列
4. SKILL.md：agent 引导触发话术（"想和 TA 联系 → `xq dm`"）
5. 测试：发信计费 / 拉黑拦截 / 通知去重 / 状态维度
6. 文档更新：design.md / cli-reference.md / cookbook.md

## 记录源

- 2026-04-23 老板讨论：确定"虚拟信封 + 信箱/通知分离 + 架构中立"三原则
- OpenClaw 源码 `src/gateway/hooks.ts:243` 验证 `/hooks/agent` 协议可用
- 放弃的收费模型：点数 / 推荐位 / 会员订阅 / 竞价 / 送礼分成（老板 2026-04-23 明确砍掉）
