Guide

邮件 API 速率限制:各提供商对比

Gmail、Microsoft Graph、Yahoo、Exchange EWS 和 iCloud 各自执行不同的速率限制、配额体系和限流规则。本指南用一张表格对比它们,涵盖超出限制时会遇到的 SMTP 错误码,并展示如何在不自己编写退避逻辑的情况下处理重试。

Written by Aaron de Mello Senior Engineering Manager

VerifiedCLI 3.1.11 · Gmail, Outlook · last tested May 21, 2026

命令参考: nylas email list nylas email send nylas email search

Gmail API 速率限制是什么?

Gmail API 速率限制按配额单位(quota unit)计量,而不是按原始请求数。每个 Gmail API 方法消耗的单位数不同,每个用户默认每秒获得 250 个单位。一次 messages.list 调用消耗 5 个单位,messages.get 消耗 5 个单位,messages.send 消耗 100 个单位。这意味着每个用户每秒最多发送 2 封邮件,但可以每秒列出 50 页。

根据 Google 的 Gmail API 配额文档,每用户速率限制已于 2026 年 5 月 1 日更新为 250 单位/用户/秒(此前仅跟踪每日配额)。每个项目的每日上限为 10 亿配额单位。超出任一限制都会触发 HTTP 429,并附带 Retry-After 头。

Gmail API 方法配额消耗每秒最大调用数(每用户)
messages.list5 个单位50
messages.get5 个单位50
messages.send100 个单位2
messages.modify5 个单位50
messages.trash10 个单位25
history.list2 个单位125
messages.batchGet每条 5 个单位50(按批次内每条消息计)

这套配额单位体系意味着:一个先调用 messages.list 再对每条结果调用 messages.get 的朴素同步循环,每封邮件要消耗 10 个单位。同步 1,000 封邮件总共消耗 10,000 个单位,单个用户 40 秒就能耗尽。批量端点能减少往返开销,但不会改变每封邮件的单位成本。CLI 在内部对这些调用做批处理并遵守 Retry-After 头,因此一条 nylas email list --limit 1000 命令无需任何额外代码即可处理分页和限流。

# List up to 200 Gmail messages — the CLI handles pagination and rate limits
nylas email list --limit 200 --json

Microsoft Graph 邮件速率限制是什么?

Microsoft Graph 对每个应用、每个邮箱执行每 10 分钟 10,000 次请求的限流,约合每个邮箱每秒 16 次请求。超出限制时,Graph 返回 HTTP 429,并在 Retry-After 头中指定需要等待的秒数。与 Gmail 不同,Graph 不使用单位成本体系;无论端点复杂度如何,每次请求都按 1 次计算。

根据 Microsoft 的 Graph API 限流文档,10,000 次/10 分钟的限制适用于 Outlook 邮件、日历和联系人端点。租户级限制更高(未公开,因服务而异)。通过 $batch 端点发起的批量请求在限流统计中算作 1 次请求,但每批最多 20 个操作。如果每封邮件都需要单独的 GET,邮件同步的实际上限约为每 10 分钟 3,200 封。

Graph 还对发送施加限制:Microsoft 365 商业账户每天 10,000 个收件人,Outlook.com 个人账户每天 300 封邮件。起决定作用的是收件人数量,而非邮件数量。一封发给 50 个收件人的邮件按 50 计入每日限制。

CLI 把这些限制抽象到一条命令背后。对 Outlook 邮箱运行 nylas email send 会自动处理 429 响应,并按 Retry-After 头指定的延迟重试。

# Send an email through Outlook — retries on 429 are handled by the CLI
nylas email send --to "recipient@example.com" --subject "Quarterly report" --body "Attached."

各邮件提供商的速率限制如何对比?

5 大邮件提供商的速率限制执行方式差异很大。Gmail 使用按方法计费的配额单位。Microsoft Graph 使用固定请求计数。Yahoo 和 iCloud 在 IMAP 层执行未公开的连接限制。Exchange EWS 使用并发请求限流。下表展示了对自动化邮件工作流最重要的数字:每秒请求数、每日邮件数和附件大小上限。

提供商速率限制模型实际读取数/秒每日发送限制最大附件
Gmail API配额单位(250/用户/秒)~502,000 封邮件25 MB
Microsoft Graph固定请求数(10,000/10 分钟)~1610,000 个收件人150 MB
Yahoo IMAP基于连接(未公开)~5-10500 封邮件25 MB
Exchange EWS并发请求(最多 27 个)~2710,000 个收件人35 MB(默认)
iCloud IMAP基于连接(未公开)~51,000 封邮件20 MB

"实际读取数/秒"一列反映的是 list + get 同步模式下的现实吞吐量,而非提供商文档中的理论最大值。Gmail 的单位体系使其对读取密集型工作负载最为宽松。Graph 的固定计数模型更简单,但对批量同步更严格。Yahoo 和 iCloud 不公布确切数字,上面的估算来自使用 CLI 对不同账龄账户进行的实测。

哪些 SMTP 错误码表示速率限制?

SMTP 速率限制错误分为两类:来自 REST API 的 HTTP 状态码和来自邮件服务器的 SMTP 增强状态码。HTTP 429 "Too Many Requests" 响应是 Gmail API 和 Microsoft Graph 的标准信号。SMTP 服务器使用 4.7.x 系列增强状态码。判断你看到的是哪种代码,决定了应该立即重试还是等待数小时。

代码提供商含义重试策略
HTTP 429Gmail、Graph超出配额或请求限制等待 Retry-After 头指定的时长
4.7.28Gmail SMTP滚动 24 小时窗口内发送邮件过多等待 24 小时窗口重置
4.7.0Yahoo SMTP连接或发送的临时速率限制指数退避,基础间隔 30 秒
5.7.3Exchange / Microsoft 365超出每日收件人限制无法重试,需等到下一个日历日
421iCloud SMTP并发连接过多减少连接数,60 秒后重试
HTTP 503Graph服务暂时不可用(通常与限流相关)指数退避,基础间隔 5 秒

4xx 与 5xx 增强状态码的区别很重要。Gmail 的 4.7.28 是临时性的,会自行恢复。Exchange 的 5.7.3 意味着你触到了硬性每日上限。根据 Google 的 Workspace 发送限制文档,免费 Gmail 账户每天最多发送 500 封邮件,Google Workspace 账户则为 2,000 封。CLI 会解析这些错误码并相应调整重试行为。

触发速率限制后应如何重试?

带抖动(jitter)的指数退避是应对邮件 API 速率限制的标准重试策略。该模式在每次失败后将等待时间加倍(1 秒、2 秒、4 秒、8 秒),并加入 0 到 1 秒的随机抖动,防止多个客户端同时触发同一限制时出现"惊群"问题。没有抖动时,并行 worker 的同步重试会堆积起来,进一步延长限流窗口。

根据 Google 的 API 错误处理文档,推荐的最大重试次数为 5 次,退避间隔上限为 32 秒。Microsoft 的 Graph 文档建议严格遵守 Retry-After 头的值,而不是自行计算延迟。实践中,Gmail 返回的 Retry-After 值通常为 1-60 秒,而 Graph 根据限流严重程度返回 5-300 秒。

如果你直接调用 Gmail 或 Graph API,就需要自己实现这个循环。下面的 Python 代码展示了带抖动的最小实现。每次重试将基础延迟加倍,并加入最多 1 秒的随机抖动。失败 5 次后函数抛出异常,而不是无限循环。

import time, random, requests

def call_with_backoff(url, headers, max_retries=5):
    delay = 1
    for attempt in range(max_retries):
        resp = requests.get(url, headers=headers)
        if resp.status_code != 429:
            return resp
        retry_after = int(resp.headers.get("Retry-After", delay))
        jitter = random.uniform(0, 1)
        wait = retry_after + jitter
        print(f"Rate limited. Retry {attempt + 1}/{max_retries} in {wait:.1f}s")
        time.sleep(wait)
        delay = min(delay * 2, 32)
    raise Exception("Max retries exceeded")

CLI 内部如何处理速率限制?

Nylas CLI 在平台层处理速率限制,因此你不用自己写重试逻辑。当底层 Nylas API 收到来自 Gmail、Graph 或任何已连接提供商的 429 时,会自动以指数退避重试。CLI 继承了这一行为。一条 nylas email list --limit 500 命令在幕后可能触发数十次分页 API 调用,每一次都遵守提供商的限流信号,而不会把错误暴露给你。

该平台每月在 Gmail、Outlook、Exchange、Yahoo、iCloud 和 IMAP 提供商间处理超过 12 亿次 API 调用。这样的体量意味着重试逻辑已针对上表中的每一种速率限制模式经过验证。此处描述的提供商侧行为基于提供商公开文档以及我们对 Gmail 和 Outlook 的测试;在为 Yahoo、iCloud 或 EWS 部署依赖提供商特性的假设前,请先在本地验证。

要查看包含速率限制头的原始 API 响应,在任意命令后添加 --json。JSON 输出包含暴露提供商响应头的元数据字段。这对调试串联多条 CLI 命令的脚本很有用,因为你可以检查是否遇到过 429 以及重试等待了多久。

# Fetch 500 messages with full JSON output including response metadata
nylas email list --limit 500 --json | jq '.[0:3]'

对于同步整个邮箱或发送 2,000 封邮件的群发活动这类批量操作,CLI 会在内部对请求排队,并保持在提供商限制之内。以配额允许的持续速率完整同步一个包含 10,000 封邮件的 Gmail 收件箱大约需要 3 分钟;如果可以完全无视限制,则只需大约 40 秒。

各提供商的批量操作限制是什么?

批量操作让你把多个 API 调用合并到单个 HTTP 请求中,减少往返开销,有时还能绕开按请求计数的限流。Gmail 支持每批最多 100 个调用的批量请求,而 Microsoft Graph 将批量上限设为 20 个操作。Exchange EWS 没有正式的批量端点,但通过带分页的 FindItem 支持分组操作。

根据 Google 的批量请求文档,Gmail 批量请求中的每个操作仍按其完整配额单位计费。一批 100 个 messages.get 调用消耗 500 个单位,与 100 次单独调用相同。收益在于延迟,而非配额节省。Microsoft 的 $batch 端点则不同:整批在 10,000 次/10 分钟的限流统计中算作单次请求,但其中每个操作仍独立执行,并可能单独失败。

提供商每批最大操作数是否节省配额?限流计数方式
Gmail API100否(每个操作按完整单位计费)每个操作单独计数
Microsoft Graph20是(限流按 1 次请求计)整批算作 1 次请求
Exchange EWS无正式批量端点不适用每次请求单独计数
Yahoo IMAP不适用(IMAP 协议)不适用连接级限流
iCloud IMAP不适用(IMAP 协议)不适用连接级限流

CLI 会在提供商支持的地方使用批处理。对 Gmail,它把 messages.get 调用按每批 100 个分组,以降低分页期间的延迟。对 Graph,它在每个 $batch 请求中打包最多 20 个操作,把限流优势用到极致。这些都不需要你配置;它们在 nylas email list 背后自动发生。

如何监控速率限制用量?

Gmail 通过 Google Cloud Console 的 APIs & Services > Gmail API > Quotas 暴露配额用量,你可以在那里按方法查看实时单位消耗。Microsoft Graph 在 Azure 门户的 App Registrations > 你的应用 > Performance 下提供用量数据。两个仪表盘都每 5 分钟刷新一次,并显示 30 天的历史记录,足以发现限流事件的规律。

对于基于 CLI 的工作流,在任意命令后添加 --json,并把输出通过管道传给 jq 来统计结果数并估算 API 调用量。下面的命令列出 100 封邮件、统计数量,并计算大致消耗的 Gmail 配额单位。每个 messages.list 页(每页 100 条结果)消耗 5 个单位,加上每封邮件一次 messages.get 各消耗 5 个单位,100 封邮件大约消耗 505 个配额单位。

# Count messages returned and estimate Gmail quota cost
COUNT=$(nylas email list --limit 100 --json | jq 'length')
echo "$COUNT messages fetched"
echo "Estimated quota cost: $((5 + COUNT * 5)) units"

如果你在运行周期性同步脚本,每次运行后记录数量和时间戳。一个每 5 分钟同步一次、每次拉取 200 封邮件的 cron 任务,每个周期消耗约 1,005 个单位,每天约 289,440 个单位。这远低于每日 10 亿单位的项目限制,但若扩展到数千用户就值得跟踪了。

后续步骤