DM 模块(私信)¶
dm 模块提供私信发送和收件箱查询功能,支持单条发送、批量并发发送和收件箱翻页。
目录¶
dm send — 发送单条私信¶
向指定用户发送一条私信,可选附带媒体附件。
语法¶
参数¶
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
--user-id <ID> |
string | 是 | 目标用户的 Twitter 数字 ID(非用户名) |
--text <STRING> |
string | 是 | 消息内容,最大 10000 字符 |
--media-id <ID> |
string | 否 | 媒体附件 ID(来自 upload image 命令的返回值) |
成功示例¶
twitter-cli --cookies-file cookies.txt dm send \
--user-id 783214 \
--text "Hello from twitter-cli!"
输出(单行 JSONL):
{"success":true,"data":{"user_id":"783214","event_id":"1811234567890123456","message":"Message sent successfully","media_id":null},"error":null,"meta":{"module":"dm","action":"send","elapsed_ms":519,"timestamp":"2026-04-17T10:45:00Z","cli_version":"1.0.0","schema_version":"1.0"}}
带媒体附件:
# 先上传图片获取 media_id
media_id=$(twitter-cli --cookies-file cookies.txt upload image \
--file photo.jpg --category dm-image | jq -r '.data.media_id_string')
# 发送带图片的私信
twitter-cli --cookies-file cookies.txt dm send \
--user-id 783214 \
--text "请看这张图片" \
--media-id "$media_id"
失败示例¶
{"success":false,"data":null,"error":{"code":"NOT_FOUND","message":"用户 999999 不存在或无法接收私信","retryable":false,"retry_after_secs":null,"docs_url":null,"recovery_actions":["确认 user_id 是否正确","检查目标用户是否开放私信权限"],"issue_url":null,"details":{"http_status":403}},"meta":{"module":"dm","action":"send","elapsed_ms":312,"timestamp":"2026-04-17T10:46:00Z","cli_version":"1.0.0","schema_version":"1.0"}}
data 字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 目标用户 ID(与输入相同) |
event_id |
string | 私信事件 ID(Twitter 的 snowflake ID) |
message |
string | 成功描述(固定为 "Message sent successfully") |
media_id |
string | null | 媒体 ID(如果发送了媒体附件) |
常见错误¶
| 错误码 | 原因 | 解决方法 |
|---|---|---|
INVALID_ARGS |
--text 超过 10000 字符 |
截断文本 |
AUTH_FAILED |
cookies 过期 | 重新导出 cookies |
NOT_FOUND |
用户不存在或禁止私信 | 确认用户 ID,检查对方隐私设置 |
RATE_LIMIT |
发送过于频繁 | 等待 retry_after_secs 后重试 |
dm send-batch — 批量发送私信¶
并发向多个用户发送私信。支持统一文案和从文件读取自定义文案两种模式。输出为三段式 BatchLine 格式(header / item / summary)。
语法¶
twitter-cli [全局 flags] dm send-batch \
--user-ids <ID,ID,...> \
(--text <STRING> | --texts-file <PATH>) \
[--media-id <ID>]
参数¶
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
--user-ids <ID,...> |
string | 是 | 逗号分隔的用户 ID 列表(如 783214,6253282,1234) |
--text <STRING> |
string | 二选一 | 所有用户使用相同的文案 |
--texts-file <PATH> |
path | 二选一 | 自定义文案文件,每行一条,行数必须与 user-ids 数量一致 |
--media-id <ID> |
string | 否 | 所有用户共享同一个媒体附件 ID |
--text和--texts-file必须二选一,不可同时使用。
texts-file 格式¶
每行一条文案,行数必须与 --user-ids 中的 ID 数量完全相同:
统一文案示例¶
twitter-cli --cookies-file cookies.txt dm send-batch \
--user-ids 783214,6253282,1234567890 \
--text "批量通知:系统维护将于明日进行"
自定义文案示例¶
twitter-cli --cookies-file cookies.txt dm send-batch \
--user-ids 783214,6253282,1234567890 \
--texts-file messages.txt
BatchLine 输出(完整 5 行示例)¶
{"type":"header","command":"dm send-batch","schema_version":"1.0","expected_count":3,"meta":{"module":"dm","action":"send-batch","timestamp":"2026-04-17T10:45:00Z","cli_version":"1.0.0"}}
{"type":"item","index":0,"success":true,"data":{"user_id":"783214","event_id":"1811234567890123456","message":"Message sent successfully","media_id":null}}
{"type":"item","index":1,"success":false,"error":{"code":"NOT_FOUND","message":"用户 6253282 不存在或无法接收私信","retryable":false,"retry_after_secs":null,"recovery_actions":["确认 user_id 是否正确"]}}
{"type":"item","index":2,"success":true,"data":{"user_id":"1234567890","event_id":"1811234567890123457","message":"Message sent successfully","media_id":null}}
{"type":"summary","total":3,"success_count":2,"fail_count":1,"elapsed_ms":1820}
解析批量结果¶
# 统计成功/失败数
twitter-cli --cookies-file cookies.txt dm send-batch \
--user-ids 783214,6253282 --text "Hello" | \
grep '"type":"summary"' | jq '{total: .total, ok: .success_count, fail: .fail_count}'
# 提取失败的 user_id 用于重试
twitter-cli ... | \
grep '"type":"item"' | \
jq -r 'select(.success == false) | .error.message'
item 字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | 固定 "item" |
index |
number | 在 user-ids 列表中的位置(从 0 开始) |
success |
bool | 是否发送成功 |
data |
object | null | 同 dm send 的 data(成功时) |
error |
object | null | 错误详情(失败时) |
summary 字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
total |
number | 目标用户总数 |
success_count |
number | 成功发送数量 |
fail_count |
number | 失败数量 |
elapsed_ms |
number | 批量操作总耗时(毫秒) |
常见错误¶
| 错误码 | 原因 | 解决方法 |
|---|---|---|
INVALID_ARGS |
--texts-file 行数与 user-ids 数量不符 |
确认文件行数与 ID 数一致 |
INVALID_ARGS |
同时指定 --text 和 --texts-file |
只使用其中一个 |
RATE_LIMIT |
批量触发速率限制 | 减少批次大小,添加间隔 |
dm inbox — 查询收件箱¶
获取最近的私信收件箱更新记录。
语法¶
参数¶
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
--max <N> |
number | 否 | 返回的最大条目数,默认 20 |
成功示例¶
输出:
{"success":true,"data":{"entries":[{"conversation_id":"783214-6253282","last_message_id":"1811234567890123456","last_message_text":"Hello from twitter-cli!","participants":["783214","6253282"],"unread_count":0},{"conversation_id":"783214-1234567890","last_message_id":"1811234567890123400","last_message_text":"Test message","participants":["783214","1234567890"],"unread_count":1}],"next_cursor":"1811234567890123300","entry_count":2},"error":null,"meta":{"module":"dm","action":"inbox","elapsed_ms":421,"timestamp":"2026-04-17T10:45:00Z","cli_version":"1.0.0","schema_version":"1.0"}}
失败示例¶
{"success":false,"data":null,"error":{"code":"AUTH_FAILED","message":"Twitter 返回 401,cookies 可能已过期","retryable":false,"retry_after_secs":null,"docs_url":"https://x-api-rs.es007.com/cli/getting-started/#cookies","recovery_actions":["重新从浏览器导出 cookies"],"issue_url":null,"details":{"http_status":401}},"meta":{"module":"dm","action":"inbox","elapsed_ms":128,"timestamp":"2026-04-17T10:46:00Z","cli_version":"1.0.0","schema_version":"1.0"}}
data 字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
entries |
array | 会话列表 |
entries[].conversation_id |
string | 会话 ID(格式:user1_id-user2_id) |
entries[].last_message_id |
string | 最新一条消息的 ID |
entries[].last_message_text |
string | 最新消息预览文本 |
entries[].participants |
string[] | 会话参与者 ID 列表 |
entries[].unread_count |
number | 未读消息数 |
next_cursor |
string | null | 翻页游标(为 null 表示没有更多数据) |
entry_count |
number | 本次返回的条目数 |
翻页方式¶
inbox 不直接支持 --cursor 参数(使用最新消息 ID 自动分页)。如需历史数据,使用 Inbox 模块的 Python API(client.inbox.get_user_updates)更灵活。
常见错误¶
| 错误码 | 原因 | 解决方法 |
|---|---|---|
AUTH_FAILED |
认证失败 | 更新 cookies |
RATE_LIMIT |
查询过于频繁 | 降低查询频率 |