用途
Postmark 入站处理(Inbound)用于处理收到的电子邮件。Postmark 会解析来信,并以结构化 JSON 形式投递到你的 Webhook 端点。典型用途包括:
- 邮件回复(Reply-by-email)——将回复关联回原会话线程
- 邮件转工单(Email-to-ticket)——把邮件转换为支持工单
- 文档提取——自动处理邮件附件
- 命令处理——从邮件中解析结构化数据
- 转发/路由——根据内容将邮件路由到不同服务
工作方式
流程为:发件人 → 邮件 → Postmark → 解析邮件 → POST JSON → 你的 Webhook 端点。
- 在 Postmark 服务器中配置入站地址或域名
- 设置 Webhook URL,Postmark 会向该地址 POST 解析后的邮件数据
- 接收 JSON——Postmark 处理原始邮件并投递结构化数据
- 返回 200——端点必须返回 HTTP 200 以确认接收
快速开始
- 设置入站域名——为域名配置 MX 记录或邮件转发
- 设置 Webhook URL——在 Postmark 服务器设置中设置 Inbound webhook URL
- 构建端点——创建接受入站 JSON 载荷的 HTTP POST 处理器
- 返回 200——始终以 HTTP 200 响应以确认接收
错误处理与重试
如果端点返回非 200 状态码,Postmark 会自动重试投递,最多 10 次,总时长约 10.5 小时,间隔递增:
| 重试次数 | 距上次尝试的间隔 |
|---|---|
| 1 | 1 分钟 |
| 2 | 5 分钟 |
| 3 | 10 分钟 |
| 4 | 10 分钟 |
| 5 | 10 分钟 |
| 6 | 15 分钟 |
| 7 | 30 分钟 |
| 8 | 1 小时 |
| 9 | 2 小时 |
| 10 | 6 小时 |
重要:返回 403 会立即停止所有重试——Postmark 将其视为有意拒绝。所有重试耗尽后,消息被标记为 "Failed",并在活动页面显示为 "Inbound Error"。可通过 API 手动重试失败消息(PUT /messages/inbound/{messageid}/retry)。
入站配置
有两种设置方式——MX 记录(推荐)或邮件转发。约束:每个服务器一个入站流,每个流一个域名,每个流一个 Webhook URL。
完整的 DNS 步骤、转发注意事项、重试时间表和 Webhook URL 设置方式见 references/inbound-setup.md。
Webhook 载荷
Postmark POST 到端点的 JSON 中的关键字段:
| 字段 | 说明 |
|---|---|
| From | 发件人邮箱地址 |
| Subject | 邮件主题 |
| MailboxHash | 收件地址中 + 后的哈希——主要路由机制 |
| TextBody | 完整纯文本正文(包含引用的回复) |
| StrippedTextReply | 仅回复文本——已去除引用内容 |
| HtmlBody | 完整 HTML 正文 |
| Attachments | 数组,元素为 {Name, Content, ContentType, ContentLength, ContentID} |
| MessageID | Postmark 唯一消息标识符 |
| Headers | 所有邮件头,格式为 [{Name, Value}] |
完整载荷 JSON、附件字段和邮件头线程示例见 references/payload-structure.md。
使用 MailboxHash 进行路由
使用 + 寻址将邮件路由到特定记录或会话:
- support+ticket-456@yourdomain.com → MailboxHash: "ticket-456"
- notifications+order-789@yourdomain.com → MailboxHash: "order-789"
这是将回复关联回会话或路由到特定记录的主要机制。
基础端点示例
const express = require('express');
const app = express();
app.use(express.json({ limit: '50mb' }));
app.post('/webhooks/inbound', (req, res) => {
const { From, Subject, MailboxHash, StrippedTextReply, TextBody } = req.body;
if (MailboxHash) {
// Threaded reply — parse the hash to find the related record
const [type, id] = MailboxHash.split('-');
console.log(`Reply for ${type} #${id} from ${From}`);
} else {
console.log(`New inbound email from ${From}: ${Subject}`);
}
// Always prefer StrippedTextReply for replies
const replyText = StrippedTextReply || TextBody;
res.sendStatus(200); // Must return 200
});
Node.js、Python、附件处理、邮件回复和异步处理模式见 references/handler-examples.md。
入站规则与 Messages API
可按地址或域名屏蔽不需要的发件人,并通过 API 查询/重试已处理的消息。入站规则端点和 Messages API 见 references/inbound-api.md。
常见错误
| 错误 | 修复 |
|---|---|
| 未返回 HTTP 200 | 始终返回 200——即使异步处理 |
| 意外返回 403 | 这会永久停止该消息的重试 |
| 未解析 MailboxHash | 使用 + 寻址进行路由——这是主要线程机制 |
| 使用 TextBody 而非 StrippedTextReply | StrippedTextReply 会从回复中去除引用内容 |
| 正文解析器无大小限制 | 为带附件的消息将正文解析器限制设为 50mb |
| Webhook 处理缓慢 | 异步处理(将工作入队)并立即返回 200 |
| 忽略附件的 ContentID | 带 ContentID 的附件是内联图片,不是独立文件 |
注意事项
- 每个服务器一个入站流——不同入站域名使用不同服务器
- 入站 Webhook 载荷因附件可能很大——设置合适的正文大小限制
- StrippedTextReply 去除引用内容,只给出新的回复文本
- MailboxHash 字段是收件地址中 + 后的部分——用于路由
- Headers 数组包含所有原始邮件头,用于高级处理
- 同一服务器可同时处理入站和出站邮件
- 入站处理与出站分离——不同的流、不同的配置