4、发送文本消息:文本消息格式详解、Python代码实现发送文本、消息长度限制与换行处理

文本消息,说白了就是最基础的消息类型。你想想看,机器人跟人聊天,大部分场景下就是发一段文字。但就是这看似简单的文本,里面也有不少门道。我在项目中遇到过好几次因为格式不对导致消息发送失败的情况,所以这一节咱们好好捋一捋。

4.1 文本消息的JSON格式长什么样?

企业微信的文本消息,底层走的是JSON格式。我给你拆开看看:

{
    "touser": "@all",
    "msgtype": "text",
    "agentid": 1000002,
    "text": {
        "content": "你好,世界!"
    },
    "safe": 0
}

这里每个字段都有讲究:

  • touser:发给谁。可以是具体用户ID,多个用竖线隔开,或者直接用@all发给所有人。我个人习惯在测试时先用具体用户,上线前再改成@all
  • msgtype:固定为"text",告诉企业微信这是文本消息。
  • agentid:你的应用ID,创建机器人时拿到的那个数字。
  • text.content:消息正文,就是你要说的话。
  • safe:是否保密消息。0表示不保密,1表示保密。保密消息会加密显示,不能转发复制。

重点提醒safe字段很多人会忽略。如果你发的是敏感信息,比如密码、内部数据,记得设成1。我曾经有个同事把测试环境的数据库密码明文发到群里,还好发现得早……

4.2 Python代码实现发送文本

光说不练假把式。咱们直接上代码,用Python把文本消息发出去。

首先,你得拿到access_token。这个在上一节讲过,这里我直接复用:

import requests
import json

def get_access_token(corpid, corpsecret):
    """获取企业微信access_token"""
    url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}"
    resp = requests.get(url)
    data = resp.json()
    if data.get('errcode') == 0:
        return data['access_token']
    else:
        raise Exception(f"获取token失败: {data['errmsg']}")

然后,写发送文本消息的函数:

def send_text_message(access_token, agentid, content, touser="@all", safe=0):
    """发送文本消息"""
    url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"
    
    payload = {
        "touser": touser,
        "msgtype": "text",
        "agentid": agentid,
        "text": {
            "content": content
        },
        "safe": safe
    }
    
    headers = {"Content-Type": "application/json"}
    resp = requests.post(url, data=json.dumps(payload, ensure_ascii=False), headers=headers)
    result = resp.json()
    
    if result.get('errcode') == 0:
        print("消息发送成功!")
    else:
        print(f"发送失败: {result['errmsg']}")
    
    return result

调用起来也很简单:

# 配置你的信息
corpid = "你的企业ID"
corpsecret = "你的应用Secret"
agentid = 1000002

# 获取token
token = get_access_token(corpid, corpsecret)

# 发送文本消息
send_text_message(token, agentid, "大家好,我是机器人小蓝!")

小技巧json.dumps里记得加ensure_ascii=False,不然中文会变成\u开头的Unicode编码,消息发出去就是乱码。这个坑我踩过,真的很难排查。

4.3 消息长度限制,你不得不注意

企业微信对文本消息有长度限制。具体是多少?我直接给你表格:

限制项 数值 说明
单条消息最大长度 2048字节 注意是字节,不是字符
中文占字节数 3字节 UTF-8编码下
英文/数字占字节数 1字节 ASCII字符

为什么会这样?因为企业微信后台用的是UTF-8编码。一个中文字符占3个字节,一个英文字母占1个字节。所以如果你发纯中文,最多能发2048 ÷ 3 ≈ 682个字。如果混着英文和数字,能发的字数会多一些。

我在项目中遇到过一个问题:自动发送日报时,内容太长被截断了,导致日报不完整。后来我加了个截断逻辑:

def truncate_content(content, max_bytes=2048):
    """按字节截断消息,避免超出限制"""
    encoded = content.encode('utf-8')
    if len(encoded) <= max_bytes:
        return content
    
    # 截断到最大字节数
    truncated = encoded[:max_bytes]
    # 解码回去,忽略末尾可能被截断的字符
    return truncated.decode('utf-8', errors='ignore')

警告:截断时一定要考虑字符边界。如果直接按字节截断,可能会把一个中文字符截成两半,解码时会报错。上面的代码用errors='ignore'可以自动丢弃不完整的字符,但最好还是用更精确的算法。

4.4 换行处理,让消息更易读

文本消息里怎么换行?很多人第一反应是用\n。没错,就是它。但要注意,企业微信的换行符是\n,不是\r\n,也不是<br>

看个例子:

content = "第一行内容\n第二行内容\n第三行内容"
send_text_message(token, agentid, content)

发送后,群里显示的效果是:

第一行内容
第二行内容
第三行内容

嗯,就是这么简单。但实际项目中,我经常需要拼接多行内容,比如:

def build_report_message(data):
    """构建日报消息"""
    lines = []
    lines.append("📊 今日数据日报")
    lines.append("=" * 20)
    lines.append(f"新增用户: {data['new_users']} 人")
    lines.append(f"活跃用户: {data['active_users']} 人")
    lines.append(f"订单数量: {data['orders']} 单")
    lines.append(f"总收入: ¥{data['revenue']:.2f}")
    lines.append("=" * 20)
    lines.append("发送时间: " + data['time'])
    
    return "\n".join(lines)

这样拼接出来的消息,结构清晰,阅读体验好很多。

个人经验:我习惯用列表收集每一行,最后用"\n".join()合并。这样比直接字符串拼接更清晰,也方便增删行。你想想看,如果后面要加个分隔线,直接在列表里加一行就行,多方便。

4.5 避坑指南:我踩过的那些坑

最后,分享几个我实际踩过的坑,你遇到了可以少走弯路:

  • 坑一:消息内容为空。如果content是空字符串,企业微信会返回错误。所以发送前一定要检查内容是否为空。
  • 坑二:特殊字符转义。JSON里的双引号、反斜杠需要转义。比如你想发他说:"你好",代码里要写成他说:\"你好\"
  • 坑三:换行符不生效。如果你从文件或数据库读取内容,换行符可能是\r\n,需要替换成\n。我一般用content.replace('\r\n', '\n')处理一下。
  • 坑四:emoji表情。企业微信支持emoji,但有些特殊emoji(比如肤色修饰符)可能会超出字节限制。建议发送前先测试一下。

好了,文本消息这块就讲到这里。下一节咱们聊聊更丰富的消息类型——Markdown消息,那个能排版、能加粗、能变色,比纯文本好玩多了。