通过企业微信向微信推送消息的配置文档、直推函数和可自行搭建的在线服务代码。可以看成Server酱的开源替代方案之一。

Wecom酱

通过企业微信向微信推送消息的解决方案。包括:

  1. 配置说明(本页下方)
  2. 推送函数(支持多种语言,见本页下方)
  3. 自行搭建的在线服务源码
    1. PHP版搭建说明
    2. Go版说明

企业微信应用消息配置说明

优点:

  1. 一次配置,持续使用
  2. 配置好以后,只需要微信就能收消息,不再需要安装企业微信客户端

PS:消息接口无需认证即可使用,个人用微信就可以注册

具体操作

第一步,注册企业

用电脑打开企业微信官网,注册一个企业

第二步,创建应用

注册成功后,点「管理企业」进入管理界面,选择「应用管理」 → 「自建」 → 「创建应用」

应用名称填入「Server酱」,应用logo到这里下载,可见范围选择公司名。

创建完成后进入应用详情页,可以得到应用ID( agentid )①,应用Secret( secret )②。

注意:secret推送到手机端时,只能在企业微信客户端中查看。

第三步,获取企业ID

进入「我的企业」页面,拉到最下边,可以看到企业ID③,复制并填到上方。

推送UID直接填 @all ,推送给公司全员。

第四步,推送消息到微信

进入「我的企业」 → 「微信插件」,拉到下边扫描二维码,关注以后即可收到推送的消息。

PS:如果出现接口请求正常,企业微信接受消息正常,个人微信无法收到消息的情况:

  1. 进入「我的企业」 → 「微信插件」,拉到最下方,勾选 “允许成员在微信插件中接收和回复聊天消息”

  2. 在企业微信客户端 「我」 → 「设置」 → 「新消息通知」中关闭 “仅在企业微信中接受消息” 限制条件

第五步,通过以下函数发送消息:

PS:为使用方便,以下函数没有对 access_token 进行缓存。对于个人低频调用已经够用。带缓存的实现可查看 index.php 中的示例代码(依赖Redis实现)。

PHP版:

text = ["content"=> $text]; $data->duplicate_check_interval = 600; $data_json = json_encode($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); return $response; } return false; } ">
function send_to_wecom($text, $wecom_cid, $wecom_secret, $wecom_aid, $wecom_touid = '@all')
{
    $info = @json_decode(file_get_contents("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=".urlencode($wecom_cid)."&corpsecret=".urlencode($wecom_secret)), true);
                
    if ($info && isset($info['access_token']) && strlen($info['access_token']) > 0) {
        $access_token = $info['access_token'];
        $url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token='.urlencode($access_token);
        $data = new \stdClass();
        $data->touser = $wecom_touid;
        $data->agentid = $wecom_aid;
        $data->msgtype = "text";
        $data->text = ["content"=> $text];
        $data->duplicate_check_interval = 600;

        $data_json = json_encode($data);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        
        $response = curl_exec($ch);
        return $response;
    }
    return false;
}

使用实例:

$ret = send_to_wecom("推送测试\r\n测试换行", "企业ID③", "应用ID①", "应用secret②");
print_r( $ret );

PYTHON版:

0: send_msg_url = f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}' data = { "touser":wecom_touid, "agentid":wecom_aid, "msgtype":"text", "text":{ "content":text }, "duplicate_check_interval":600 } response = requests.post(send_msg_url,data=json.dumps(data)).content return response else: return False ">
import json,requests
def send_to_wecom(text,wecom_cid,wecom_secret,wecom_aid,wecom_touid='@all'):
    get_token_url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={wecom_cid}&corpsecret={wecom_secret}"
    response = requests.get(get_token_url).content
    access_token = json.loads(response).get('access_token')
    if access_token and len(access_token) > 0:
        send_msg_url = f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}'
        data = {
            "touser":wecom_touid,
            "agentid":wecom_aid,
            "msgtype":"text",
            "text":{
                "content":text
            },
            "duplicate_check_interval":600
        }
        response = requests.post(send_msg_url,data=json.dumps(data)).content
        return response
    else:
        return False

使用实例:

ret = send_to_wecom("推送测试\r\n测试换行", "企业ID③", "应用ID①", "应用secret②");
print( ret );

TypeScript 版:

import request from 'superagent'

async function sendToWecom(body: {
  text: string
  wecomCId: string
  wecomSecret: string
  wecomAgentId: string
  wecomTouid?: string
}): Promise<{ errcode: number; errmsg: string; invaliduser: string }> {
  body.wecomTouid = body.wecomTouid ?? '@all'
  const getTokenUrl = `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${body.wecomCId}&corpsecret=${body.wecomSecret}`
  const getTokenRes = await request.get(getTokenUrl)
  const accessToken = getTokenRes.body.access_token
  if (accessToken?.length <= 0) {
    throw new Error('获取 accessToken 失败')
  }
  const sendMsgUrl = `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accessToken}`
  const sendMsgRes = await request.post(sendMsgUrl).send({
    touser: body.wecomTouid,
    agentid: body.wecomAgentId,
    msgtype: 'text',
    text: {
      content: body.text,
    },
    duplicate_check_interval: 600,
  })
  return sendMsgRes.body
}

使用实例:

sendToWecom({
  text: '推送测试\r\n测试换行',
  wecomAgentId: '应用ID①',
  wecomSecret: '应用secret②',
  wecomCId: '企业ID③',
})
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log(err)
  })

.NET Core 版:

(new RestClient(getTokenUrl) .Get(new RestRequest()).Content).access_token; System.Console.WriteLine(token); if (!String.IsNullOrWhiteSpace(token)) { var request = new RestRequest(); var client = new RestClient($"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}"); var data = new { touser = weComTouId, agentid = weComAId, msgtype = "text", text = new { content = text }, duplicate_check_interval = 600 }; string serJson = JsonConvert.SerializeObject(data); System.Console.WriteLine(serJson); request.Method = Method.POST; request.AddHeader("Accept", "application/json"); request.Parameters.Clear(); request.AddParameter("application/json", serJson, ParameterType.RequestBody); return client.Execute(request).Content; } return "-1"; } } ">
using System;
using RestSharp;
using Newtonsoft.Json;
namespace WeCom.Demo
{
    class WeCom
    {   
        public  string SendToWeCom(
            string text,// 推送消息
            string weComCId,// 企业Id①
            string weComSecret,// 应用secret②
            string weComAId,// 应用ID③
            string weComTouId = "@all")
        {
            // 获取Token
            string getTokenUrl = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={weComCId}&corpsecret={weComSecret}";
            string token = JsonConvert
            .DeserializeObject<dynamic>(new RestClient(getTokenUrl)
            .Get(new RestRequest()).Content).access_token;
            System.Console.WriteLine(token);
            if (!String.IsNullOrWhiteSpace(token))
            {
                var request = new RestRequest();
                var client = new RestClient($"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}");
                var data = new
                {
                    touser = weComTouId,
                    agentid = weComAId,
                    msgtype = "text",
                    text = new
                    {
                        content = text
                    },
                    duplicate_check_interval = 600
                };
                string serJson = JsonConvert.SerializeObject(data);
                System.Console.WriteLine(serJson);
                request.Method = Method.POST;
                request.AddHeader("Accept", "application/json");
                request.Parameters.Clear();
                request.AddParameter("application/json", serJson, ParameterType.RequestBody);
                return client.Execute(request).Content;
            }
            return "-1";
        }
}

使用实例:

   static void Main(string[] args)
        {   // 测试
            Console.Write(new WeCom().SendToWeCom(
            "msginfo",
            "企业Id①"
            , "应用secret②",
            "应用ID③"
            ));
        }

    }

其他版本的函数可参照上边的逻辑自行编写,欢迎PR。

Comments
  • add: Go版新增图片类型的推送消息

    add: Go版新增图片类型的推送消息

    具体工作(go-wecomchan):

    1. 兼容原文本消息推送接口,新增支持推送图片消息,并直接返回企业微信的response json串,原先接口无返回数据
    2. 调整redis缓存机制,原先可能存在access_token已失效,但仍然存在于redis中并被使用,导致报错
    3. Dockerfile中新增一行用于替换alpinelinux的国内源
    4. 相应调增README.md内容
  • 腾讯报错

    腾讯报错

    {"errorCode":1,"errorMessage":"Process exited before completing request","requestId":"954a3c773d9e987c100b46927b4d01d5","statusCode":439}

  • docker版怎么用POST请求发送文本消息

    docker版怎么用POST请求发送文本消息

    # curl -X POST -d '{"sendkey":"mysendkey","msg_type":"text","msg":"test msg"}' 'http://localhost:48080/wecomchan' curl: (52) Empty reply from server 查看wecomchan的日志 2022/05/10 01:23:33 wecomchan.go:94: 企业微信获取access_token接口返回==> map[access_token:a_valid_token errcode:0 errmsg:ok expires_in:7200] 2022/05/10 01:23:33 wecomchan.go:248: sendkey 错误,请检查 2022/05/10 01:23:33 server.go:3139: http: panic serving 172.17.0.1:40915: sendkey 错误,请检查

    请问大佬是docker版的不支持POST发送文本消息吗? 不支持的话能不能增加这个功能呢?现实情况下,消息可能会有很多行,用GET发送实在太不方便了。 万分感谢

  • 云函数报错

    云函数报错

    {"errorCode":1,"errorMessage":"Resource limit exceed for function [dingdong]","requestId":"1a04a1006a8d321f05031308b4fd695d","statusCode":432}

  • PHP 版能否使用 post 参数

    PHP 版能否使用 post 参数

    能不能用 post 方式使用 wecom 酱的 php 版本

    post body 为{"msg": "post_test","test": "text1"},php 设置为echo send_to_wecom(@$_POST['msg'], WECOM_CID, WECOM_AID, WECOM_SECRET, WECOM_TOUID);

    尝试过下列修改:

    • php 配置 enable_post_data_reading=on
    • $raw = file_get_contents('php://input'); echo $raw;
    • hearder 修改 Content-Type=application/x-www-data-urlencoded

    但是,均提示 empty content,无法从 $_POST['msg'] 获取数值。

  • 做了一个类似的项目,希望参与serverchan生态建设

    做了一个类似的项目,希望参与serverchan生态建设

  • go版本推送的消息里面有空格就报错

    go版本推送的消息里面有空格就报错

    curl --location --request GET "http://192.168.123.3:8080/wecomchan?sendkey={set_a_sendkey}&msg={推送的消息 推送的消息 }&msg_type=text"

  • 使用的百度云函数搭建,提示没有用户

    使用的百度云函数搭建,提示没有用户

    {"Code":"NotFountException","Cause":"no router","Message":"Not Found","Status":404,"Type":"User"} 确认四处要修改的都已经修改

  • 关于我在2022/09/08日的搭建过程中,发现的配置问题

    关于我在2022/09/08日的搭建过程中,发现的配置问题

    在白名单那里走了很多的弯路,原以为可以很快的搭建好的,毕竟我比较小白,过程就不说了。 说说解决方法,按照平常的方法搭建,最后测试Hello的时候会显示是不信任的IP,解决方法如下 打开云函数控制台,进入wecomchan项目的函数配置,然后找到下面的公网IP,进行勾选,等待一段时候后, 会分配一个固定的公网IP! 将此IP添加进 企业微信的可信IP 这样方可以按照教程在调用云函数,实现之前的功能

  • 请问怎么发送给指定的人

    请问怎么发送给指定的人

    用的是docker,启动容器时参数WECOM_TOUID="@all",那在命令行运行时怎么指定发给某人或者某几个人? 需要每次重新建立容器然后TOUID=@xx? 还是在调用的命令行后面直接加参数?这样应该比较合理。 再就是这个企业微信的TOUID怎么获取,文档里链接的企业微信官方文档打开是空白的。

Related tags