← RFC Reference

RFC 8620: JMAP — JSON 元应用协议

Standards Track Mail Access Protocols Published March 2026
ELI5: IMAP 是在 1990 年代设计的,当时客户端通过原始 TCP 套接字与服务器通信,使用自定义文本协议。JMAP 的概念相同——访问邮箱、管理文件夹、同步更改——但使用每位开发者都已了解的工具:JSON over HTTPS。这是一个类似 REST 的电子邮件 API。不需要套接字管理、不需要解析奇怪的文本响应、不需要扩展协商。只需 POST 一个 JSON 请求,获取 JSON 响应。

为什么存在

IMAP有效,但它承载了数十年的复杂性:

JMAP解决了所有这些问题。它是无状态的(每个请求是独立的),使用HTTPS(通过任何代理和防火墙工作),使用JSON(每种语言都有解析器),并通过EventSource或Web Push将推送通知定义为一等特性。

工作原理

服务发现

客户端通过well-known URI发现JMAP端点:

GET https://example.com/.well-known/jmap
{
  "capabilities": {
    "urn:ietf:params:jmap:core": { ... },
    "urn:ietf:params:jmap:mail": { ... }
  },
  "apiUrl": "https://jmap.example.com/api/",
  "uploadUrl": "https://jmap.example.com/upload/{accountId}/",
  "downloadUrl": "https://jmap.example.com/download/{accountId}/{blobId}/{name}",
  "eventSourceUrl": "https://jmap.example.com/events/"
}

进行API调用

所有JMAP操作作为单个POST发送到API URL。请求体包含方法调用数组,响应包含对应的结果:

POST https://jmap.example.com/api/
{
  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
  "methodCalls": [
    ["Mailbox/get", { "accountId": "u1234", "ids": null }, "a"]
  ]
}

{
  "methodResponses": [
    ["Mailbox/get", {
      "accountId": "u1234",
      "state": "m42",
      "list": [
        { "id": "mb1", "name": "收件箱", "totalEmails": 142 },
        { "id": "mb2", "name": "已发送", "totalEmails": 87 },
        { "id": "mb3", "name": "存档", "totalEmails": 4210 }
      ]
    }, "a"]
  ]
}

批处理和后向引用

多个方法调用可在一个请求中批处理。后向引用让一个调用使用前一个调用的结果:

"methodCalls": [
  ["Email/query", {
    "accountId": "u1234",
    "filter": { "inMailbox": "mb1", "after": "2025-03-01T00:00:00Z" },
    "sort": [{ "property": "receivedAt", "isAscending": false }],
    "limit": 10
  }, "q"],
  ["Email/get", {
    "accountId": "u1234",
    "#ids": { "resultOf": "q", "name": "Email/query", "path": "/ids" },
    "properties": ["from", "subject", "receivedAt", "preview"]
  }, "g"]
]

这会搜索收件箱并在一个HTTP往返中获取前10个结果——这需要多个IMAP命令。

关键技术细节

状态字符串和同步

每个JMAP /get响应都包含一个state字符串。要同步更改,客户端使用上次已知状态调用/changes:

["Email/changes", { "accountId": "u1234", "sinceState": "e789" }, "c"]

["Email/changes", {
  "oldState": "e789",
  "newState": "e801",
  "created": ["em500", "em501"],
  "updated": ["em480"],
  "destroyed": ["em312"]
}, "c"]

客户端随后仅获取创建/更新的项。这比IMAP的CONDSTORE更有效,因为它同时在所有邮箱中工作,不需要持久连接。

推送通知

JMAP定义了两种推送机制:

Foo/get、Foo/set、Foo/query模式

JMAP为每种数据类型使用统一的方法模式:

方法 用途
Foo/get 按ID获取对象
Foo/changes 获取自状态以来已更改的对象ID
Foo/set 创建、更新或销毁对象
Foo/query 搜索/过滤并排序,返回匹配的ID
Foo/queryChanges 对前一个查询结果的增量更新

对于电子邮件,Foo是Email、Mailbox、Thread、EmailSubmission等。这种一致性意味着一旦你理解了一种数据类型,你就理解了它们所有。

常见错误

可交付性影响

Related RFCs