ARTICLE · 1126245
VBA 发送企业微信群机器人消息:让 Excel 数据自己飞进群里
VBA 发送企业微信群机器人消息:让 Excel 数据自己飞进群里
报表做完还得手动截图发群——这是很多人的日常。其实企业微信群自带一个「机器人」,给它一个网址,任何程序都能往里发消息。这一篇我们就用 VBA 打通这条线:Excel 里的数据,算完自动飞进群里,还能 @ 到具体的人、带颜色标识重点,全程不需要服务器、不需要企业认证、不花一分钱。
一、学习目标
掌握企业微信群机器人的 Webhook 机制:一个网址 = 一个发消息的通道。 掌握 VBA 用 WinHttp 发 POST 请求,并解决中文 UTF-8 编码这个必踩的坑。 做出日报自动推送:读表 → 拼消息 → 发送 → 判断成功失败 → 每天定时自动跑。
二、知识点精讲
1. 三分钟拿到你的 Webhook 地址
企业微信群里点右上角 → 群机器人 → 添加机器人 → 起个名字(比如「数据小助手」)→ 复制它给出的 Webhook 地址:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa后面那一长串 key 就是你的钥匙。拿到这个地址,任何能发 HTTP 请求的程序都能往这个群发消息——这就是机器人最简单的原理。
⚠️ 安全提醒(官方明确强调):这个地址等于群里的"发言权",谁拿到都能发垃圾消息。不要分享到 GitHub、博客等公开地方。 本篇代码里我们把它放在标准模块顶部的常量里,或者读单元格,别硬编码到要分享的文件里。
2. 消息类型与硬性限制
企业微信群机器人支持七八种消息类型,最常用的三种:
text | 2048 字节 | |||
markdown | 4096 字节 | |||
markdown_v2 | 4096 字节 |
还有 image(图片,base64 编码前不超过 2MB)、news(图文,1~8 条)、file(文件,需先上传拿 media_id)等。
三个必须记住的数字:
文本消息 2048 字节、markdown 4096 字节——注意是字节不是字符,一个中文占 3 字节,所以文本消息实际大概只能放 680 个汉字; 每个机器人每分钟最多发 20 条,超了返回错误码 45009被限流;消息是单向的:机器人只能发,不能收,也删不掉已发出的消息。
3. markdown 支持哪些语法(这是最容易踩的坑)
企业微信的 markdown 只支持一个语法子集,比通用的 Markdown 少很多:
# 标题(1~6 级,# 与文字之间要有空格)**加粗**[链接文字](https://example.com)`行内代码`> 引用文字<font color="info">绿色</font><font color="comment">灰色</font><font color="warning">橙红色</font>重点:markdown 类型不支持表格、不支持图片、不支持列表的自动编号。 想要表格必须用 markdown_v2——但 markdown_v2 又不支持颜色和 @人。
结论:想发数据表格就用 markdown_v2,想发带颜色的告警就用 markdown,两者不能兼得。日常工作里绝大多数通知场景,用带颜色的 markdown 效果更好。
4. VBA 的第一个坑:UTF-8 编码
这是本篇最关键的技术点。VBA 里的字符串是 Unicode,而企业微信接口只接受 UTF-8 编码的字节流。直接 Send 字符串,中文必然乱码或直接报错。
标准解法是用 ADODB.Stream 做一次编码转换。但这里还藏着一个更隐蔽的坑:
ADODB.Stream 以 UTF-8 写入时会自动加上 3 个字节的 BOM 头(EF BB BF)。 这 3 个字节会让企业微信的 JSON 解析器一头雾水,返回"无效的 JSON"或 93000 错误——代码看起来完全没问题,就是不成功。
唯一的解法:读字节时跳过前 3 个字节。
st.Position = 3 ' 跳过 UTF-8 BOM,这一行是整个教程的命门三、实战案例
案例 1(简单):发出第一条消息
先把三个基础零件备好:UTF-8 转字节、JSON 转义、发送函数。这三个函数后面所有案例都会反复用。
完整代码(标准模块 m企业微信):
Option Explicit' ⚠️ 把这里换成你自己的机器人 KEY(只填 key= 后面那一串)Public Const 机器人KEY As String = "693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa"' ========== 零件一:字符串转 UTF-8 字节数组 ==========Private Function UTF8字节(文本 As String) As Byte() Dim st As Object Set st = CreateObject("ADODB.Stream") st.Type = 2 ' adTypeText st.Charset = "utf-8" st.Open st.WriteText 文本 st.Position = 0 st.Type = 1 ' adTypeBinary st.Position = 3 ' 跳过 UTF-8 BOM(EF BB BF),否则接口报错 UTF8字节 = st.Read st.Close Set st = NothingEnd Function' ========== 零件二:JSON 字符串转义 ==========Public Function JSON转义(s As String) As String Dim r As String r = Replace(s, "\", "\\") ' 反斜杠必须第一个替换 r = Replace(r, """", "\""") r = Replace(r, vbCrLf, "\n") r = Replace(r, vbCr, "\n") r = Replace(r, vbLf, "\n") r = Replace(r, vbTab, "\t") JSON转义 = rEnd Function' ========== 零件三:真正发送 ==========Public Function 发送企业微信(消息JSON As String) As String Dim http As Object Dim 地址 As String 地址 = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" & 机器人KEY Set http = CreateObject("WinHttp.WinHttpRequest.5.1") http.Open "POST", 地址, False http.setRequestHeader "Content-Type", "application/json; charset=utf-8" http.SetTimeouts 5000, 5000, 10000, 10000 ' 连接/发送/接收超时(毫秒) http.Send UTF8字节(消息JSON) 发送企业微信 = 字节转文本(http.ResponseBody) Set http = NothingEnd Function' ========== 辅助:响应字节转文本(避免返回中文乱码)==========Private Function 字节转文本(数据 As Variant) As String Dim st As Object Set st = CreateObject("ADODB.Stream") st.Type = 1 st.Open st.Write 数据 st.Position = 0 st.Type = 2 st.Charset = "utf-8" 字节转文本 = st.ReadText st.Close Set st = NothingEnd Function' ========== 案例 1:发送纯文本 ==========Sub 发送文本消息() Dim 内容 As String, 返回 As String 内容 = "【VBA 测试】Excel 数据小助手已上线,时间为 " & Format(Now, "yyyy-mm-dd hh:nn:ss") 返回 = 发送企业微信("{""msgtype"":""text"",""text"":{""content"":""" & _ JSON转义(内容) & """}}") If InStr(返回, """errcode"":0") > 0 Then MsgBox "发送成功!去群里看看。", vbInformation Else MsgBox "发送失败:" & 返回, vbCritical End IfEnd Sub操作步骤:
在企业微信群里加好机器人,复制 Webhook 地址,把 key=后面那串填到机器人KEY常量里。Alt + F11打开 VBE,插入标准模块,把模块名改成m企业微信,粘贴上面全部代码。Alt + F8运行发送文本消息。群里立刻收到消息,Excel 弹窗提示「发送成功」。
三个新手必踩的坑:① 直接
Send字符串 → 中文乱码,必须走UTF8字节;② 忘了st.Position = 3→ 接口报错,因为 BOM 头混进了 JSON;③ JSON 里的双引号在 VBA 里要写成两个"",这是 VBA 的转义规则。
案例 2(中等):发一条带颜色的漂亮通知
纯文本太单调。换用 markdown 类型,加上标题、引用和三种颜色,一眼看出重点;再配上 @ 人,让该看的人立刻收到。
完整代码(追加到同一模块):
' ========== 组装 markdown 消息体 ==========Public Function 拼Markdown(内容 As String) As String 拼Markdown = "{""msgtype"":""markdown"",""markdown"":{""content"":""" & _ JSON转义(内容) & """}}"End Function' ========== 案例 2-1:带颜色的 markdown 通知 ==========Sub 发送彩色通知() Dim 内容 As String, 返回 As String ' 注意:内容里的换行用 vbLf,经 JSON转义 后会变成 \n 内容 = "## 今日数据汇总" & vbLf & _ "> 销售额:<font color=""warning"">128,600 元</font>" & vbLf & _ "> 订单数:<font color=""info"">356 单</font>" & vbLf & _ "> 库存预警:<font color=""comment"">3 项待处理</font>" & vbLf & _ "> 环比昨日:<font color=""info"">+12.4%</font>" & vbLf & vbLf & _ "详情请查看共享盘 `\\server\报表\日报.xlsx`" 返回 = 发送企业微信(拼Markdown(内容)) Debug.Print 返回 ' 在「立即窗口」看接口返回 MsgBox "已发送,返回:" & 返回, vbInformationEnd Sub' ========== 案例 2-2:文本消息 + @指定人(按手机号)==========Sub 发送并艾特人() Dim 内容 As String, 返回 As String 内容 = "【紧急】库存低于安全线,请立即安排补货。" ' mentioned_mobile_list 填对方手机号,@all 表示全员 返回 = 发送企业微信("{""msgtype"":""text"",""text"":{""content"":""" & _ JSON转义(内容) & """,""mentioned_mobile_list"":[""13800001111"",""@all""]}}") MsgBox "返回:" & 返回, vbInformationEnd Sub操作步骤:
把代码追加到 m企业微信模块(拼Markdown是 Public,案例 3 还要用)。运行 发送彩色通知→ 群里收到一条带标题、四行引用、橙红/绿/灰三色的通知卡片。把 发送并艾特人里的手机号改成同事的(或留@all),运行后群成员会收到提醒。
关于颜色的用法:
warning(橙红)标异常和金额、info(绿)标正常和增长、comment(灰)标次要说明。一条消息里颜色别超过三种,否则重点就没了。另外注意:markdown类型不支持表格,想发数据表格得改用markdown_v2,但它不支持颜色和 @人。
案例 3(实用):Excel 日报自动推送(含错误处理与定时)
最实用的场景来了:表格里放好当天数据,VBA 自动读出来、拼成消息发进群,并且能判断成功失败、能定时自动跑。
第一步:准备数据区
在 日报数据 工作表里按这样放(B 列放值):
第二步:完整代码
' ========== 估算 UTF-8 字节数(用于长度保护)==========Public Function 字节长度(s As String) As Long On Error GoTo 空文本 字节长度 = UBound(UTF8字节(s)) + 1 Exit Function空文本: 字节长度 = 0End Function' ========== 案例 3:推送销售日报 ==========Sub 推送销售日报() Dim ws As Worksheet Dim 日期 As String, 销售额 As Double, 订单数 As Long, 预警 As String, 环比 As String Dim 内容 As String, 返回 As String ' 1) 读数据(表不存在就直接挡掉,不让代码崩) On Error Resume Next Set ws = ThisWorkbook.Worksheets("日报数据") On Error GoTo 0 If ws Is Nothing Then MsgBox "找不到「日报数据」工作表。", vbExclamation Exit Sub End If 日期 = ws.Range("B1").Text 销售额 = Val(ws.Range("B2").Value) 订单数 = CLng(Val(ws.Range("B3").Value)) 预警 = ws.Range("B4").Text 环比 = ws.Range("B5").Text ' 2) 拼 markdown 内容 = "## " & 日期 & " 销售日报" & vbLf & _ "> 销售额:<font color=""warning"">" & Format(销售额, "#,##0") & " 元</font>" & vbLf & _ "> 订单数:<font color=""info"">" & 订单数 & " 单</font>" & vbLf & _ "> 库存预警:<font color=""comment"">" & 预警 & "</font>" & vbLf & _ "> 环比昨日:<font color=""info"">" & 环比 & "</font>" & vbLf & vbLf & _ "报送人:数据小助手" ' 3) 长度保护:markdown 上限 4096 字节 If 字节长度(内容) > 4096 Then MsgBox "消息内容 " & 字节长度(内容) & " 字节,超过 4096 上限,请精简后再发。", vbExclamation Exit Sub End If ' 4) 发送并判断结果 返回 = 发送企业微信(拼Markdown(内容)) If InStr(返回, """errcode"":0") > 0 Then MsgBox "日报推送成功!", vbInformation ElseIf InStr(返回, "45009") > 0 Then MsgBox "发送太频繁了(每分钟最多 20 条),请等一分钟再试。", vbExclamation ElseIf InStr(返回, "93000") > 0 Then MsgBox "Webhook 地址无效,请检查机器人 KEY 是否复制完整。", vbCritical Else MsgBox "推送失败,接口返回:" & vbCrLf & 返回, vbCritical End IfEnd Sub' ========== 定时:每天 9:00 自动推送 ==========Sub 安排每日推送() Dim 目标时间 As Date 目标时间 = Date + TimeValue("09:00:00") If 目标时间 <= Now Then 目标时间 = 目标时间 + 1 ' 今天已过 9:00,排到明天 Application.OnTime 目标时间, "推送销售日报" MsgBox "已排定下一次推送:" & Format(目标时间, "yyyy-mm-dd hh:nn"), vbInformationEnd Sub第三步:让定时任务开机自动排上(ThisWorkbook 代码模块)
Private Sub Workbook_Open() ' 打开文件时把今天的推送排上,过程末尾会重排明天 Call 安排每日推送End Sub操作步骤:
建好「日报数据」表,按上面的表格填数据。 把案例 3 的代码追加到 m企业微信,安排每日推送粘进标准模块。双击 VBE 左侧 ThisWorkbook,粘贴Workbook_Open。先手动跑一次 推送销售日报→ 群里收到日报,Excel 弹「日报推送成功!」。保存为 .xlsm并保持文件打开(OnTime需要工作簿处于打开状态),到点自动推送。
三个工程细节:① 先判断表是否存在再读值,避免文件换版本就报错;②
Val()读数字能兼容单元格里混了文本的情况;③ 发完一条要重排下一天的定时(把Call 安排每日推送加在推送销售日报末尾即可),否则只有今天发一条——OnTime只响一次,不循环。
四、本篇小结
原理极简:一个 Webhook 网址就是一个发消息通道,VBA 用 WinHttp 发个 POST 就完事。 编码是关键:必须转 UTF-8 字节,且跳过 ADODB.Stream自动加的 3 字节 BOM,否则必失败。类型要选对:要颜色和 @人用 markdown(不支持表格),要发数据表格用markdown_v2(不支持颜色和 @人)。限制记心间:文本 2048 字节、markdown 4096 字节、每分钟最多 20 条,错误码 0成功 /93000地址无效 /45009太频繁。安全第一:Webhook 地址等同群里的发言权,绝不公开。
把这篇和前面的定时任务、报表生成串起来,你就能做出「算完自动发、出问题自动报警」的完整闭环——早上到公司,报表已经在群里了。
五、进阶方向
发图片:把图表截图转 base64(配 md5)用 image类型发送,适合发趋势图;发文件:先调 upload_media上传拿到media_id,再用file类型把 Excel 报表本体发进群;多群分发:把多个群的 Webhook 存进一张配置表,循环发送,一次通知所有相关群; 配合告警场景:库存低于安全线、销售额异常波动时自动触发,用 warning颜色 + @负责人,让问题不过夜。