企业微信的群组支持给群组添加群机器人,添加完群机器人后就可以使用群机器人在群内同步消息。群机器人创建者可以在机器人详情页看到该机器人特有的 webhook url。开发者可以向这个地址发起 HTTP POST 请求,即可实现给该群组发送消息。
启用示例:
示例代码:
import requests import json webhook = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx' header = { "Content-Type": "application/json", "Charset": "UTF-8" } data = { "msgtype": "text", "text": { "content": "Hello World!" } } data = json.dumps(data) info = requests.post(url=webhook, data=data, headers=header)
群机器人发送消息的一些限制:
- 目前暂不支持设置消息回调配置。支持设置机器人主动推送。
- 群聊可添加的机器人数量暂无上限。
- 机器人发消息的频率:每个机器人发送的消息不能超过 20 条/分钟。
- 文件大小在 5B~20M 之间;图文消息的图片链接,支持 JPG、PNG 格式,较好的效果为大图 1068×455,小图 150×150
- 图片(base64 编码前)最大不能超过 2M,支持 JPG,PNG 格式。
群机器人支持的消息类型
当前自定义机器人支持文本(text)、markdown(markdown)、图片(image)、图文(news)、文件(file)、语音(voice)、模板卡片(template_card)七种消息类型。机器人的 text/markdown 类型消息支持在 content 中使用 <@userid> 扩展语法来 @群成员
文件上传接口
素材上传得到 media_id,该 media_id 仅三天内有效。media_id 只能是对应上传文件的机器人可以使用请求方式:POST(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=KEY&type=TYPE
使用 multipart/form-data POST 上传文件或语音,文件标识名为 “media”
参数说明:
参数 | 必须 | 说明 |
key | 是 | 调用接口凭证,机器人 webhook url 中的 key 参数 |
type | 是 | 文件类型,分别有语音(voice)和普通文件(file) |
POST 的请求包中,form-data 中媒体文件标识,应包含有filename、filelength、content-type 等信息。filename 标识文件展示的名称。比如,使用该 media_id 发消息时,展示的文件名由该字段控制请求示例:
import requests def upload_media(file_path, key, media_type): url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={key}&type={media_type}" # 打开文件并准备上传 with open(file_path, 'rb') as file: # 准备 multipart/form-data 数据 files = { 'media': (file_path, file, 'application/octet-stream') } # 发送 POST 请求 response = requests.post(url, files=files) # 检查响应状态 if response.status_code == 200: return response.json() else: response.raise_for_status()
返回数据:
{ "errcode": 0, "errmsg": "ok", "type": "file", "media_id": "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0", "created_at": "1380000000" }
参数说明:
参数 | 说明 |
type | 文件类型,分别有语音(voice)和普通文件(file) |
media_id | 媒体文件上传后获取的唯一标识,3 天内有效 |
created_at | 媒体文件上传时间戳 |
上传的文件限制:
所有类型的文件大小均要求大于 5 个字节
- 普通文件(file):文件大小不超过 20M
- 语音(voice):文件大小不超过 2M,播放长度不超过 60s,仅支持 AMR 格式
文本类型消息
{ "msgtype": "text", "text": { "content": "广州今日天气:29 度,大部分多云,降雨概率:60%", "mentioned_list": ["wangqing", "@all"], "mentioned_mobile_list": ["13800001111", "@all"] } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 消息类型,此时固定为 text |
content | 是 | 文本内容,最长不超过 2048 个字节,必须是 utf8 编码 |
mentioned_list | 否 | userid 的列表,提醒群中的指定成员(@某个成员),@all 表示提醒所有人,如果开发者获取不到 userid,可以使用 mentioned_mobile_list |
mentioned_mobile_list | 否 | 手机号列表,提醒手机号对应的群成员(@某个成员),@all 表示提醒所有人 |
Python封装:
import requests import json # 发送文本消息 def send_text(webhook, content, mentioned_list=None, mentioned_mobile_list=None): header = { "Content-Type": "application/json", "Charset": "UTF-8" } data = { "msgtype": "text", "text": { "content": content, "mentioned_list": mentioned_list, "mentioned_mobile_list": mentioned_mobile_list } } data = json.dumps(data) response = requests.post(url=webhook, data=data, headers=header) return response
markdown类型消息
{ "msgtype": "markdown", "markdown": { "content": "实时新增用户反馈<font color=\"warning\">132例</font>,请相关同事注意。\n >类型:<font color=\"comment\">用户反馈</font> >普通用户反馈:<font color=\"comment\">117例</font> >VIP用户反馈:<font color=\"comment\">15例</font>" } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 消息类型,此时固定为markdown |
content | 是 | markdown内容,最长不超过4096个字节,必须是utf8编码 |
支持的markdown语法
目前支持的markdown语法是如下的子集:
标题(支持1至6级标题,注意#与文字中间要有空格)
# 标题一 ## 标题二 ### 标题三 #### 标题四 ##### 标题五 ###### 标题六
加粗
**bold**
链接
[这是一个链接](http://work.weixin.qq.com/api/doc)
行内代码段(暂不支持跨行)
`code`
引用
>引用文字
字体颜色(只支持3种内置颜色)
<font color="info">绿色</font> <font color="comment">灰色</font> <font color="warning">橙红色</font>
Python封装:
import requests import json # 发送markdown消息 def send_md(webhook, content): header = { "Content-Type": "application/json", "Charset": "UTF-8" } data = { "msgtype": "markdown", "markdown": { "content": content } } data = json.dumps(data) response = requests.post(url=webhook, data=data, headers=header) return response
图片类型消息
{ "msgtype": "image", "image": { "base64": "DATA", "md5": "MD5" } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 消息类型,此时固定为image |
base64 | 是 | 图片内容的base64编码 |
md5 | 是 | 图片内容(base64编码前)的md5值 |
注:图片(base64编码前)最大不能超过2M,支持JPG,PNG格式
Python封装:
```python import requests import json import base64 import hashlib # 发送图片消息 def send_image(webhook, image_path): header = { "Content-Type": "application/json", "Charset": "UTF-8" } # 读取图片文件并进行base64编码 with open(image_path, "rb") as image_file: image_data = image_file.read() base64_data = base64.b64encode(image_data).decode('utf-8') # 计算图片的MD5值 md5_hash = hashlib.md5(image_data).hexdigest() data = { "msgtype": "image", "image": { "base64": base64_data, "md5": md5_hash } } data = json.dumps(data) response = requests.post(url=webhook, data=data, headers=header) return response
图文类型消息
{ "msgtype": "news", "news": { "articles": [ { "title": "中秋节礼品领取", "description": "今年中秋节公司有豪礼相送", "url": "www.qq.com", "picurl": "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png" } ] } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 消息类型,此时固定为news |
articles | 是 | 图文消息,一个图文消息支持1到8条图文 |
title | 是 | 标题,不超过128个字节,超过会自动截断 |
description | 否 | 描述,不超过512个字节,超过会自动截断 |
url | 是 | 点击后跳转的链接。 |
picurl | 否 | 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图1068*455,小图150*150。 |
文件类型消息
{ "msgtype": "file", "file": { "media_id": "3a8asd892asd8asd" } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 消息类型,此时固定为file |
media_id | 是 | 文件id,通过下文的文件上传接口获取 |
语音类型消息
{ "msgtype": "voice", "voice": { "media_id": "MEDIA_ID" } }
参数 | 是否必填 | 说明 |
msgtype | 是 | 语音类型,此时固定为voice |
media_id | 是 | 语音文件id,通过下文的文件上传接口获取 |
模版卡片类型
文本通知模版卡片
{ "msgtype": "template_card", "template_card": { "card_type": "text_notice", "source": { "icon_url": "https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0", "desc": "企业微信", "desc_color": 0 }, "main_title": { "title": "欢迎使用企业微信", "desc": "您的好友正在邀请您加入企业微信" }, "emphasis_content": { "title": "100", "desc": "数据含义" }, "quote_area": { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "appid": "APPID", "pagepath": "PAGEPATH", "title": "引用文本标题", "quote_text": "Jack:企业微信真的很好用~\nBalian:超级好的一款软件!" }, "sub_title_text": "下载企业微信还能抢红包!", "horizontal_content_list": [ { "keyname": "邀请人", "value": "张三" }, { "keyname": "企微官网", "value": "点击访问", "type": 1, "url": "https://work.weixin.qq.com/?from=openApi" }, { "keyname": "企微下载", "value": "企业微信.apk", "type": 2, "media_id": "MEDIAID" } ], "jump_list": [ { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "title": "企业微信官网" }, { "type": 2, "appid": "APPID", "pagepath": "PAGEPATH", "title": "跳转小程序" } ], "card_action": { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "appid": "APPID", "pagepath": "PAGEPATH" } } }
请求参数
参数 | 必须 | 说明 | |
msgtype | String | 是 | 消息类型,此时的消息类型固定为 template_card |
template_card | Object | 是 | 具体的模版卡片参数 |
template_card 的参数说明
参数 | 类型 | 必须 | 说明 |
card_type | String | 是 | 模版卡片的模版类型,文本通知模版卡片的类型为 text_notice |
source | Object | 否 | 卡片来源样式信息,不需要来源样式可不填写 |
source.icon_url | String | 否 | 来源图片的 url |
source.desc | String | 否 | 来源图片的描述,建议不超过13个字 |
source.desc_color | Int | 否 | 来源文字的颜色,目前支持:0(默认)灰色,1黑色,2红色,3绿色 |
main_title | Object | 是 | 模版卡片的主要内容,包括一级标题和标题辅助信息 |
main_title.title | String | 否 | 一级标题,建议不超过26个字。模版卡片主要内容的一级标题 main_title.title 和二级普通文本 sub_title_text 必须有一项填写 |
main_title.desc | String | 否 | 标题辅助信息,建议不超过30个字 |
emphasis_content | Object | 否 | 关键数据样式 |
emphasis_content.title | String | 否 | 关键数据样式的数据内容,建议不超过10个字 |
emphasis_content.desc | String | 否 | 关键数据样式的数据描述内容,建议不超过15个字 |
quote_area | Object | 否 | 引用文献样式,建议不与关键数据共用 |
quote_area.type | Int | 否 | 引用文献样式区域点击事件,0或不填代表没有点击事件,1代表跳转 url,2代表跳转小程序 |
quote_area.url | String | 否 | 点击跳转的 url,quote_area.type 是1时必填 |
quote_area.appid | String | 否 | 点击跳转的小程序的 appid,quote_area.type 是2时必填 |
quote_area.pagepath | String | 否 | 点击跳转的小程序的 pagepath,quote_area.type 是2时选填 |
quote_area.title | String | 否 | 引用文献样式的标题 |
quote_area.quote_text | String | 否 | 引用文献样式的引用文案 |
sub_title_text | String | 否 | 二级普通文本,建议不超过112个字。模版卡片主要内容的一级标题 main_title.title 和二级普通文本 sub_title_text 必须有一项填写 |
horizontal_content_list | Object[] | 否 | 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6 |
horizontal_content_list.type | Int | 否 | 模版卡片的二级标题信息内容支持的类型,1是 url,2是文件附件,3代表点击跳转成员详情 |
horizontal_content_list.keyname | String | 是 | 二级标题,建议不超过5个字 |
horizontal_content_list.value | String | 否 | 二级文本,如果 horizontal_content_list.type 是2,该字段代表文件名称(要包含文件类型),建议不超过26个字 |
horizontal_content_list.url | String | 否 | 链接跳转的 url,horizontal_content_list.type 是1时必填 |
horizontal_content_list.media_id | String | 否 | 附件的media_id,horizontal_content_list.type 是2时必填 |
horizontal_content_list.userid | String | 否 | 成员详情的 userid,horizontal_content_list.type 是3时必填 |
jump_list | Object[] | 否 | 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3 |
jump_list.type | Int | 否 | 跳转链接类型,0或不填代表不是链接,1代表跳转 url,2代表跳转小程序 |
jump_list.title | String | 是 | 跳转链接样式的文案内容,建议不超过13个字 |
jump_list.url | String | 否 | |
jump_list.appid | String | 否 | 跳转链接的小程序的 appid,jump_list.type 是 2 时必填 |
jump_list.pagepath | String | 否 | 跳转链接的小程序的 pagepath,jump_list.type 是 2 时选填 |
card_action | Object | 是 | 整体卡片的点击跳转事件,text_notice 模版卡片中该字段为必填项 |
card_action.type | Int | 是 | 卡片跳转类型,1 代表跳转 url,2 代表打开小程序。text_notice 模版卡片中该字段取值范围为 [1,2] |
card_action.url | String | 否 | 跳转事件的 url,card_action.type 是 1 时必填 |
card_action.appid | String | 否 | 跳转事件的小程序的 appid,card_action.type 是 2 时必填 |
card_action.pagepath | String | 否 | 跳转事件的小程序的 pagepath,card_action.type 是 2 时选填 |
图文展示模版卡片
{ "msgtype": "template_card", "template_card": { "card_type": "news_notice", "source": { "icon_url": "https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0", "desc": "企业微信", "desc_color": 0 }, "main_title": { "title": "欢迎使用企业微信", "desc": "您的好友正在邀请您加入企业微信" }, "card_image": { "url": "https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0", "aspect_ratio": 2.25 }, "image_text_area": { "type": 1, "url": "https://work.weixin.qq.com", "title": "欢迎使用企业微信", "desc": "您的好友正在邀请您加入企业微信", "image_url": "https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0" }, "quote_area": { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "appid": "APPID", "pagepath": "PAGEPATH", "title": "引用文本标题", "quote_text": "Jack:企业微信真的很好用~\nBalian:超级好的一款软件!" }, "vertical_content_list": [ { "title": "惊喜红包等你来拿", "desc": "下载企业微信还能抢红包!" } ], "horizontal_content_list": [ { "keyname": "邀请人", "value": "张三" }, { "keyname": "企微官网", "value": "点击访问", "type": 1, "url": "https://work.weixin.qq.com/?from=openApi" }, { "keyname": "企微下载", "value": "企业微信.apk", "type": 2, "media_id": "MEDIAID" } ], "jump_list": [ { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "title": "企业微信官网" }, { "type": 2, "appid": "APPID", "pagepath": "PAGEPATH", "title": "跳转小程序" } ], "card_action": { "type": 1, "url": "https://work.weixin.qq.com/?from=openApi", "appid": "APPID", "pagepath": "PAGEPATH" } } }
请求参数
参数 | 类型 | 必须 | 说明 |
msgtype | String | 是 | 模版卡片的消息类型为 template_card |
template_card | Object | 是 | 具体的模版卡片参数 |
template_card 的参数说明
参数 | 类型 | 必须 | 说明 |
card_type | String | 是 | 模版卡片的模版类型,图文展示模版卡片的类型为 news_notice |
source | Object | 否 | 卡片来源样式信息,不需要来源样式可不填写 |
source.icon_url | String | 否 | 来源图片的 url |
source.desc | String | 否 | 来源图片的描述,建议不超过 13 个字 |
source.desc_color | Int | 否 | 来源文字的颜色,目前支持:0(默认)灰色,1 黑色,2 红色,3 绿色 |
main_title | Object | 是 | 模版卡片的主要内容,包括一级标题和标题辅助信息 |
main_title.title | String | 是 | 一级标题,建议不超过 26 个字 |
main_title.desc | String | 否 | 标题辅助信息,建议不超过 30 个字 |
card_image | Object | 是 | 图片样式 |
card_image.url | String | 是 | 图片的 url | Float | 否 | 图片的宽高比,宽高比要小于2.25,大于1.3,不填该参数默认1.3 |
image_text_area | Object | 否 | 左图右文样式 |
image_text_area.type | Int | 否 | 左图右文样式区域点击事件,0或不填代表没有点击事件,1代表跳转url,2代表跳转小程序 |
image_text_area.url | String | 否 | 点击跳转的url,image_text_area.type是1时必填 |
image_text_area.appid | String | 否 | 点击跳转的小程序的appid,必须是与当前应用关联的小程序,image_text_area.type是2时必填 |
image_text_area.pagepath | String | 否 | 点击跳转的小程序的pagepath,image_text_area.type是2时选填 |
image_text_area.title | String | 否 | 左图右文样式的标题 |
image_text_area.desc | String | 否 | 左图右文样式的描述 |
image_text_area.image_url | String | 是 | 左图右文样式的图片url |
quote_area | Object | 否 | 引用文献样式,建议不与关键数据共用 |
quote_area.type | Int | 否 | 引用文献样式区域点击事件,0或不填代表没有点击事件,1代表跳转url,2代表跳转小程序 |
quote_area.url | String | 否 | 点击跳转的url,quote_area.type是1时必填 |
quote_area.appid | String | 否 | 点击跳转的小程序的appid,quote_area.type是2时必填 |
quote_area.pagepath | String | 否 | 点击跳转的小程序的pagepath,quote_area.type是2时选填 |
quote_area.title | String | 否 | 引用文献样式的标题 |
quote_area.quote_text | String | 否 | 引用文献样式的引用文案 |
vertical_content_list | Object[] | 否 | 卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4 |
vertical_content_list.title | String | 是 | 卡片二级标题,建议不超过26个字 |
vertical_content_list.desc | String | 否 | 二级普通文本,建议不超过112个字 |
horizontal_content_list | Object[] | 否 | 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6 |
horizontal_content_list.type | Int | 否 | 模版卡片的二级标题信息内容支持的类型,1是url,2是文件附件,3代表点击跳转成员详情 |
horizontal_content_list.keyname | String | 是 | 二级标题,建议不超过5个字 |
horizontal_content_list.value | String | 否 | 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过26个字 |
horizontal_content_list.url | String | 否 | 链接跳转的url,horizontal_content_list.type是1时必填 |
horizontal_content_list.media_id | String | 否 | 附件的media_id,horizontal_content_list.type是2时必填 |
horizontal_content_list.userid | String | 否 | 成员详情的userid,horizontal_content_list.type是3时必填 |
jump_list | Object[] | 否 | 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3 |
jump_list.type | Int | 否 | 跳转链接类型,0或不填代表不是链接,1代表跳转url,2代表跳转小程序 |
jump_list.title | String | 是 | 跳转链接样式的文案内容,建议不超过13个字 |
jump_list.url | String | 否 | 跳转链接的url,jump_list.type是1时必填 |
jump_list.appid | String | 否 | 跳转链接的小程序的appid,jump_list.type是2时必填 |
jump_list.pagepath | String | 否 | 跳转链接的小程序的pagepath,jump_list.type是2时选填 |
card_action | Object | 是 | 整体卡片的点击跳转事件,news_notice模版卡片中该字段为必填项 |
card_action.type | Int | 是 | |
card_action.url | String | 否 | 跳转事件的url,card_action.type是1时必填 |
card_action.appid | String | 否 | 跳转事件的小程序的appid,card_action.type是2时必填 |
card_action.pagepath | String | 否 | 跳转事件的小程序的pagepath,card_action.type是2时选填 |
重复的轮子:
- https://github.com/cosco-chiyz/wegroupchatbot
- https://github.com/GentleCP/corpwechatbot
- https://github.com/codepkgs/wechat-robot
参考链接: