响应与 Webhook
收件人回传的一切——投票、表单提交、评分、抽奖——都会按项目收集。它会通过两种方式回传给你:仪表盘中的按收件人响应视图,以及一个可选的Webhook,在每个互动到达的瞬间就推送到你自己的端点。
仪表盘中的按收件人响应
打开仪表盘 → 你的邮件 → 响应。这封邮件收集到的每一个互动都会按收件人分组,并与项目的数据源关联。每一组都会显示谁作了回答——他们的邮箱地址以及所在行的其他字段——以及做了什么:哪个模块、哪个操作、提交的数值,以及时间。
归因通过与保护实时预览链接相同的已签名令牌完成。当邮件根据数据源进行了个性化时,每位收件人的链接都带有绑定到其所在行的令牌,携带有效令牌到达的互动会被归因到那一行。没有携带令牌到达的互动(例如来自一封未做个性化处理的邮件的投票)仍会被计数——它们会被列在一个单独的匿名分组中。
原始事件列表按分页展示(最新在前):加载完最新一页之后,一个加载更多操作会获取更早的事件。下面的所有内容——汇总统计、直方图、转化路径和趋势——都不受这种分页的影响;它们都是预先计算好的,始终覆盖项目的完整历史。
订单、订单履行与退款
任何带有商品模块的项目都会在其响应页面上获得一张订单表——每次结账一行,包含买家、金额、状态和下单时间。
- 一旦付款完成,买家会立即自动收到邮件:数字商品会收到发货内容,实体订单会收到"正在准备发货"的确认通知。
- 对于实体订单,发货后点击标记为已履行——MailInApp 本身不处理物流,但一旦你切换这个状态,它会立即给买家发一封发货通知邮件。
- 对任意已付款订单点击退款,即可通过你连接的 Stripe 账户撤销这笔款项;买家会收到一封退款确认邮件。如果一次销售恰好在最后一件库存售出的同一时刻完成,同样的邮件也会自动发出——MailInApp 会给买家退款,而不是悄悄超卖。
- 联系买家会打开一张预填该订单上下文信息的支持工单——这是直接向买家询问某件事最快的方式。
以用途为导向的核心指标
如果一个项目设置了用途(调研问卷、促销、通讯简报或活动),响应页面会以该用途最关心的那一个数字作为核心指标:调研问卷是响应率,促销是已互动收件人数,通讯简报和活动是已跟踪打开数。事务性项目以及未设置用途的项目会直接跳到下方的转化路径和汇总统计。可以随时在页面标题旁的下拉菜单中更改或清除用途;这只会影响突出显示哪个数字,绝不会影响记录的内容。
CSAT、CES 与 NPS 汇总统计
每个评分模块都会在收件人列表上方获得一个汇总统计:响应数、平均分,以及一个直方图(平均分背后的分布——一个 4.1 的平均分可能掩盖了它究竟是清一色的 4 分,还是 5 分和 1 分两极分化)。NPS 风格的模块会显示推荐者/中立者/贬损者数量,以及 −100 到 100 的分数,而不是单纯的平均分。响应分布明细会按选项为投票模块提供同样的信息。
一个参与转化路径(已发送 → 已打开(约)→ 已响应)显示在这些汇总统计之上。每个模块的响应趋势图表(按天或按周分桶)会显示平均值随时间的变化——一次定期调查的价值在于趋势线,而不是某一次的快照。它只有在某个模块累积了至少两个时间桶的数据后才会渲染。
调查问卷题目汇总统计
每个表单模块都会像评分和投票模块一样获得一份按题目的汇总统计。多选题、复选框题、线性量表题和星级评分题会得到一个显示各选项计数的柱状图;自由文本题(短文本、长文本、邮箱、数字、电话、日期)会得到一个响应数量,加上少量的示例答案。多页调查问卷的汇总方式与单页调查问卷完全相同——只有在完成所有页面之后,一次提交才会被计数,因此一份未完成的调查问卷绝不会显示为部分响应。
这些投票、评分和调查问卷题目结果并不是数据的终点——它们中的任何一个都可以直接绑定到未来邮件中的图表模块上,绑定数据源选择"营销活动响应",无需人工重新录入。参见将图表绑定到真实数据。
作业与成绩册
每个至少有一次完成或提交记录的作业模块都会在成绩册表上方获得一张统计卡片(完成数、迟交完成数、提交数)。该表每个学生一行,每个作业一列,以绿色显示"已完成"或提交的答案,如果是在模块的截止时间之后到达则显示为红色。尚无响应的作业不会占据表格空间。与其他任何汇总统计一样,它都是预先计算好的,覆盖项目的完整历史,而两种CSV 导出都包含每个模块的作业列。
点击热力图
在汇总统计下方,点击热力图会按点击次数对每个带纯链接的模块——按钮、带链接的图片、社交图标——进行排名,柱状条的长度和深浅按相对量级缩放。关于哪些会被计入、哪些不会,参见点击如何被跟踪。
滚动深度转化路径
滚动深度转化路径显示实时预览访问者中到达每个 25/50/75/100% 里程碑的比例,让你了解人们是提前离开还是读到了末尾。它只反映对托管实时预览页面的访问,而不是已发出邮件本身——原因参见滚动深度。
A/B 测试与自动获胜者
以多个变体发送(参见发送)会在响应页面上添加一个变体对比:每个变体的打开率、点击率和响应率并排展示,当前领先者会按测试所使用的指标进行标注。每位收件人都会根据其邮箱地址被确定性地分配到某个变体,所以重发和重试绝不会打乱谁看到了哪个变体。结果是按项目累计的,覆盖它曾经运行过的每一次 A/B 发送,而不仅仅是最近一次。
一个变体并不局限于主题文案的差异;它也可以更改发件人身份,或整封邮件的内容。一个更改了内容的变体自身的投票/测验/RSVP 响应和打开数会被跟踪在那个项目自己的响应页面上,而不会并入这个对比,因为互动验证会把一次提交绑定到它实际渲染所使用的那个具体项目。对比面板会链接到那个项目,而不是显示一个容易误导人的零。
自动挑选获胜者会把一次手动的 A/B 测试变成一个自动运行的测试。选择一个测试比例(例如,把名单中的 20% 拆分给各个变体发送)、决定前需要等待多长时间,以及以哪个指标来决定:打开、点击、邮件内响应,或营收。邮件内响应(投票/测验/RSVP 完成)是推荐的默认指标,因为它不像打开跟踪那样受 Apple 邮件隐私保护的影响。
等待时间结束后,MailInApp 会挑选出按收件人计算的比率表现最好的那个变体。这绝不是一个原始总数,所以一个只是在测试中被发送给了更多人的变体不会仅凭数量就看起来像获胜者。获胜的变体会发送给最初测试时被保留下来的其余所有人。如果结果是平局,或样本量太小,MailInApp 会回退到变体 1,并明确标注这一点,而绝不会宣布一个虚假的获胜者。响应页面上的状态横幅会准确显示测试目前处于哪个状态:仍在决定中、已决定、平局,或样本量过小。
发送时间优化
适用于 Pro 及以上套餐。在每位收件人自己的最佳时间发送不会让一次发送中的所有人同时收到邮件,而是查看每位联系人自己的打开时间历史——他们实际最常在 UTC 的哪个小时打开你的邮件——并把邮件留到那个时间点再发出。任何还没有足够打开历史、无法形成可靠信号的收件人,则会直接落回普通的即时发送。
这在手动发送、定时发送计划以及旅程自身的发送步骤中都以相同方式生效;对于没有信号的收件人,定时发送计划仍会按其自身配置的小时发送,与优化功能上线前的行为一致。目前它不能与同一次发送中的自动获胜者测试结合使用,因为一个被延迟发送的收件人在获胜者决定时点还未被计入。
按字段细分
使用按字段细分可以按数据源中的任意字段对同一批汇总统计进行分桶——按客服人员统计平均 CSAT、按套餐统计 NPS,等等。所在行在发送之后被删除或缩减的收件人会归入**(未知)分桶;如果一个自由文本字段产生了超过 20 个不同的取值,较小的分桶会折叠进一个末尾的其他**分组,以避免视图爆炸式增长。
CSV 导出
响应页面上的下载 CSV 会导出一个宽表、每位收件人一行的文件:每个数据源字段、首次打开时间,以及每个互动模块一列(以其题目作为列标题)。追问问题的答案会得到自己的 <question> — follow-up 列。第二个原始事件导出则为分析人员提供每个事件一行(收件人、模块、操作、数值、时间戳)的长格式数据。
调查问卷生命周期
一个项目可以设置截止日期和/或响应数量上限(maxResponses)。一旦达到其中任意一个,新的互动事件就会被拒绝——实时预览会显示一条已关闭的提示,而不是互动模块,静态内容仍会照常显示——响应页面会显示调查问卷当前是否已关闭。不会有任何内容被追溯性过滤:已经记录的响应会继续保留在你的数据中。
应用内低分警报
除了下方 Webhook 的 lowScore 标志之外,一个项目还可以列出最多几个邮箱地址,直接接收通知——不需要 Zapier/Make 步骤。每当一个评分响应超过其模块配置的阈值,MailInApp 就会(通过你自己的SMTP 设置)向这些地址发送邮件,内容包含问题、分数、已知的收件人身份,以及一个直达响应页面的链接。如果没有配置 SMTP 中继,警报会被静默跳过——Webhook 仍会照常触发。警报按项目、按小时设置上限,以避免一波低分涌入淹没你的中继。
重建汇总数据
汇总统计、转化路径和趋势都由一份预先计算好的按项目汇总数据提供,随着事件到达持续更新——因此无论项目积累了多少历史数据,它们都能保持快速响应。如果一个项目显示出异常偏低或为零的总数,很可能是因为它在这份汇总数据存在之前就已经收集过响应;在其响应页面上点击一次重建汇总数据,即可把它的完整事件历史重新回放进汇总数据中。新建的项目从不需要这样做。
Webhook
如果你更希望让数据落入自己的系统——CRM、电子表格、自动化工具——可以在同一个响应页面上配置一个 Webhook:输入一个 HTTPS URL 并点击启用。
会发生两件事:
- 系统会向你展示一个签名密钥(
whsec_…)——请立即复制它,它只会显示这一次。它存储在服务器端,之后在所有地方都会被遮蔽,与 MailInApp 中所有凭据一样。 - 从此以后,每个互动一旦被记录,就会立即以 JSON 形式 POST 到你的 URL。
你可以随时轮换密钥(会生成并展示一个新密钥,同样只显示一次)或移除该 Webhook。
负载内容
{
"type": "interaction.received",
"projectId": "abc123",
"event": {
"campaignId": "abc123",
"blockId": "poll-1",
"blockType": "poll",
"action": "vote",
"value": { "option": "Blue" },
"recipient": "row:3",
"projectId": "abc123",
"receivedAt": 1752480000000
},
"recipient": {
"key": "row:3",
"row": { "email": "[email protected]", "first_name": "Ada" }
},
"lowScore": false
}
event.value就是收集到的数据本身——所选的投票选项、表单的字段值、星级评分数。- 对于匿名互动,
recipient为null。对于已归因的互动,key是该收件人在你数据源中的行索引("row:3"= 第四行)。 recipient.row——收件人的完整数据行——只在数据源为托管型时才会包含。对于API 型数据源,我们不会在每次互动时都调用你的端点;请在你自己一端按行索引进行关联。- 当事件是评分模块上的一次
rate操作,且其数值达到或低于该模块配置的警报阈值时,lowScore为true——这是 Zapier/Make 自动化(或你自己的应用内警报)用来过滤并通知客服负责人的信号。在非评分事件上,或该模块未配置阈值时,此字段会被完全省略。
验证签名
每次投递都经过签名,以便你的端点确认它确实来自 MailInApp。会发送两个请求头:
| 请求头 | 内容 |
| --- | --- |
| X-MailInApp-Timestamp | 签名生成的时间,单位为毫秒的 epoch 时间戳 |
| X-MailInApp-Signature | v1= 后接十六进制的 HMAC-SHA256(secret, timestamp + "." + rawBody) |
根据原始请求体(在任何 JSON 解析之前)计算预期签名,并使用常数时间比较进行核对。拒绝过期的时间戳可以阻止重放的投递:
import { createHmac, timingSafeEqual } from "node:crypto";
function isValidDelivery(headers, rawBody, secret) {
const timestamp = headers["x-mailinapp-timestamp"];
const given = Buffer.from(headers["x-mailinapp-signature"] ?? "");
const expected = Buffer.from(
"v1=" +
createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex"),
);
if (given.length !== expected.length || !timingSafeEqual(given, expected)) {
return false;
}
// Reject deliveries signed more than 5 minutes ago (replay protection).
return Math.abs(Date.now() - Number(timestamp)) < 5 * 60 * 1000;
}
投递机制
- 首次投递即时进行,之后自动重试。 投递会在 5 秒后超时;任何非
2xx的响应(超时、连接失败,或错误状态码)都被视为失败。事件总是会先存储在 MailInApp 中,因此一次未送达的投递不会丢失任何数据——请把 Webhook 当作一个实时信号,把响应视图当作权威依据。 - 带退避的自动重试。 失败的投递会按递增的间隔重试——大约 1 分钟、5 分钟、30 分钟、2 小时,然后 6 小时——每次都针对你 Webhook当前的 URL 和密钥,因此轮换后的密钥或更新后的 URL 会自动被采用。如果所有重试都仍然失败,该次投递会自行停止重试,但绝不会被丢弃。
- 手动重新投递。 任何仍处于失败状态的投递(重试中或已耗尽重试次数)都会显示在响应页面的失败的投递下,附有上次失败的原因和一个重新投递按钮——在你修复了自己这边的问题之后,这个按钮很有用,不必等待下一次预定的重试。
- 绝不阻碍收件人。 投递发生在收件人的互动已经被确认之后;一个缓慢或损坏的端点绝不会延迟或使他们的投票或提交失败。
- 快速响应。 尽快返回任意
2xx,把繁重的处理放到异步中进行。
关于信任的提示: 互动端点出于必要性而必须是公开的(收件箱无法进行身份验证),因此匿名事件在设计上是未经身份验证的。已归因的事件受到已签名收件人令牌的保护。请验证投递签名,并把
event.value当作用户输入来处理。