{"id":13427738,"url":"https://github.com/blinkbean/dingtalk","last_synced_at":"2025-03-16T00:32:09.778Z","repository":{"id":57531746,"uuid":"277213732","full_name":"blinkbean/dingtalk","owner":"blinkbean","description":"golang钉钉机器人客户端。支持文本、链接、Markdown、ActionCard、FeedCard类型消息的发送，Outgoing机器人消息的接收。通过钉钉机器人接口和不同消息的封装，达到简单快速发送不同类型消息的目的。","archived":false,"fork":false,"pushed_at":"2024-08-15T13:25:03.000Z","size":267,"stargazers_count":232,"open_issues_count":0,"forks_count":57,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-08-15T15:17:24.697Z","etag":null,"topics":["dingding","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blinkbean.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-05T01:52:38.000Z","updated_at":"2024-08-15T15:17:27.720Z","dependencies_parsed_at":"2024-05-09T08:37:30.992Z","dependency_job_id":"a81fafe4-def1-4caa-9e73-3b6706f2e0c8","html_url":"https://github.com/blinkbean/dingtalk","commit_stats":null,"previous_names":["liyuxinger/dingtalk"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blinkbean%2Fdingtalk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blinkbean%2Fdingtalk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blinkbean%2Fdingtalk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blinkbean%2Fdingtalk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blinkbean","download_url":"https://codeload.github.com/blinkbean/dingtalk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221631813,"owners_count":16855012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dingding","golang"],"created_at":"2024-07-31T01:00:39.590Z","updated_at":"2024-10-27T05:30:24.506Z","avatar_url":"https://github.com/blinkbean.png","language":"Go","readme":"# Dingtalk\n\n\u003cdiv align=center\u003e\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/blinkbean/dingtalk)](https://goreportcard.com/report/github.com/blinkbean/dingtalk)\n[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg?style=flat)](https://github.com/blinkbean/dingtalk)\n[![License](https://img.shields.io/github/license/blinkbean/dingtalk.svg?style=flat)](https://github.com/blinkbean/dingtalk)\n\n[![Release](https://img.shields.io/github/v/release/blinkbean/dingtalk?style=flat)](https://github.com/blinkbean/dingtalk/releases)\n[![GitHub pull requests](https://img.shields.io/github/issues-pr/blinkbean/dingtalk?style=flat)](https://github.com/blinkbean/dingtalk/pulls)\n[![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/blinkbean/dingtalk?style=flat)](https://github.com/blinkbean/dingtalk/pulls?q=is%3Apr+is%3Aclosed)\n[![GitHub issues](https://img.shields.io/github/issues/blinkbean/dingtalk?style=flat)](https://github.com/blinkbean/dingtalk/issues)\n[![GitHub closed issues](https://img.shields.io/github/issues-closed/blinkbean/dingtalk?style=flat)](https://github.com/blinkbean/dingtalk/issues?q=is%3Aissue+is%3Aclosed)\n![Stars](https://img.shields.io/github/stars/blinkbean/dingtalk?style=flat)\n![Forks](https://img.shields.io/github/forks/blinkbean/dingtalk?style=flat)\n\n\u003c/div\u003e\n\n## 钉钉机器人消息封装——Golang\n\n目前自定义机器人支持\n- [OutGoing](#outgoing) `新`\n- [文本（Text）](#text类型)\n- [链接（Link）](#link类型)\n- [Markdown](#markdown类型)\n- ActionCard\n    - [整体跳转](#整体跳转actioncard类型)\n    - [独立跳转](#独立跳转actioncard类型)\n- [FeedCard](#feedcard类型)\n\n- 添加钉钉群：**35451012**，执行dingtalk_test.go测试方法可直接查看以下消息内容。\n[机器人官方文档](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq)\n\n## 使用\n### 创建钉钉群机器人\n1. 选择添加`自定义`机器人。\n2. 安全设置\n    共有关键词、加签、IP白名单三种设置，需要根据情况进行选择。\n    ![Xnip2020-07-05_15-55-24.jpg](https://i.loli.net/2020/07/05/4XqHG2dOwo8StEu.jpg)\n3. 选择`自定义关键词`，这里设置的关键词在初始化机器人的时候会用到。\n### 获取\n-   ```go\n    go get github.com/blinkbean/dingtalk\n    ```\n### 初始化\n-   ```go\n    // key 创建钉钉机器人需要设置的关键词，默认为`.`\n    func InitDingTalk(tokens []string, key string) *dingTalk\n    \n    // 加签方式创建钉钉机器人\n    // 加签机器人 access_token和secret一一对应，在创建机器人是获取\n    func InitDingTalkWithSecret(tokens string, secret string) *DingTalk\n    ```\n-   ```go\n    import \"github.com/blinkbean/dingtalk\"\n    \n    func main() {\n        // 单个机器人有单位时间内消息条数的限制，如果有需要可以初始化多个token，发消息时随机发给其中一个机器人。\n        var dingToken = []string{\"7bd675b66646ba890046c2198257576470099e1bda0770bad7dd6684fb1e0415\"}\n        cli := dingtalk.InitDingTalk(dingToken, \".\")\n        cli.SendTextMessage(\"content\")\n    }\n    ```\n    \n### OutGoing\n- 钉钉OutGoing机器人原理\n  \u003e 给钉钉机器人绑定一个HTTP类型的POST接口，通过@群机器人，将消息发送到指定外部服务，还可以将外部服务的响应结果返回到群组。\n\n- 配置步骤\n 1. 创建钉钉群机器人时选中 `是否开启Outgoing机制`。\n 2. 配置POST地址，外网是可访问的接口地址，如：`http://robot.blinkbean.com/outgoing` 。\n 3. 当前未做Token相关逻辑，填写内容不影响测试和使用。\n ![OutGoing.jpg](https://i.loli.net/2021/09/05/XgHph96ZFv3NdST.jpg)\n- 钉钉发送的消息格式\n    ```json\n    {\n        \"atUsers\":[\n            {\n                \"dingtalkId\":\"$:LWCP_v1:$1h0bmSzcLCHncx0lCt3Bb/UVz7xv/8vh*\"\n            }],\n        \"chatbotUserId\":\"$:LWCP_v1:$1hbmLCHncx0lCt3Bb/UVz7x/8vh*\",\n        \"conversationId\":\"cidkkCwvtlh1L0RmFuhmashi*==\",\n        \"conversationTitle\":\"Blinkbean\",\n        \"conversationType\":\"2\",\n        \"createAt\":1295212438950,\n        \"isAdmin\":false,\n        \"isInAtList\":true,\n        \"msgId\":\"msgm/bJkKjTupFM7ZoRF/eKR*==\",\n        \"msgtype\":\"text\",\n        \"sceneGroupCode\":\"project\",\n        \"senderId\":\"$:LWCP_v1:$x4wFOct/DGctv96o4IxxB*==\",\n        \"senderNick\":\"blinkbean\",\n        \"sessionWebhook\":\"https://oapi.dingtalk.com/robot/sendBySession?session=6d69b333f243db32d42c11sda9de620*\",\n        \"sessionWebhookExpiredTime\":1595212438350,\n        \"text\":{\n            \"content\":\" hello\"\n        }\n    }\n    ```\n- 方法及可选参数\n    \u003e 通过命令注册的方式，简化新命令增加操作，方便命令及其绑定方法的管理。\n\n    ```go\n    //接口方法\n    type ExecFunc func(args []string) []byte\n  \n    // 注册方法\n    func RegisterCommand(name string, execFunc ExecFunc, arity int, isAdmin bool) {\n    \tcmdTable[name] = \u0026command{\n    \t\texecutor: execFunc,\n    \t\tarity:    arity,\n    \t\tisAdmin:  isAdmin,\n    \t}\n    }\n    \n    // Handler\n    type OutGoingHandler struct{}\n    ```\n- 使用\n    ```go\n    // 自定义方法\n    outgoingFunc := func(args []string) []byte {\n        // do what you want to\n        return NewTextMsg(\"hello\").Marshaler()\n    }\n\n    // 自定义方法注册到handler\n  \tRegisterCommand(\"hello\", outgoingFunc, 2, true)\n  \n    // 启动http服务\n  \thttp.Handle(\"/outgoing\", \u0026OutGoingHandler{})\n  \t_ = http.ListenAndServe(\":8000\", nil)\n    ```\n- 本地测试\n    1. 执行dingtalk_test.go TestOutGoing 方法启动http服务\n    2. 执行以下curl命令（只保留了部分参数）\n        ```shell script\n        curl --location --request POST '127.0.0.1:8000/outgoing' \\\n        --header 'Content-type: application/json' \\\n        --data-raw '    {\n                \"isAdmin\":true,\n                \"msgtype\":\"text\",\n                \"text\":{\n                    \"content\":\"hello\"\n                }\n            }'\n        ```\n    3. 获取返回结果\n       ```json\n       {\n           \"msgtype\": \"text\",\n           \"text\": {\n               \"content\": \"hello\"\n           },\n           \"at\": {}\n       }\n       ```\n- ![Xnip2021-09-05_17-09-21.jpeg](https://i.loli.net/2021/09/05/cP4IdKhlxbs1mSn.jpg)\n\n### Text类型\n- 方法及可选参数\n    ```go\n    // 方法定义\n    SendTextMessage(content string, opt ...atOption) error\n\n    // 可选参数\n    // @所有人\n    WithAtAll()\n    \n    // @指定群成员\n    WithAtMobiles(mobiles []string)\n    ```\n- 使用\n    ```go\n    // at所有人\n    cli.SendTextMessage(\"content\", WithAtAll())\n\n    // at指定群成员\n    mobiles := []string{\"131********\"}\n    cli.SendTextMessage(\"content\", WithAtMobiles(mobiles))\n    ```\n- ![Xnip2020-07-05_10-46-59.jpg](https://i.loli.net/2020/07/05/LXErbH1KiRGstQ7.jpg)\n\n### Link类型\n- 方法\n    ```go\n    // 方法定义\n    SendLinkMessage(title, text, picUrl, msgUrl string) error\n    ```\n- 使用\n    ```go\n    cli.SendLinkMessage(title, text, picUrl, msgUrl)\n    ```\n- ![Xnip2020-07-05_10-25-33.jpg](https://i.loli.net/2020/07/05/wDG1sMPlU7XZQfr.jpg)\n\n### Markdown类型\n- 方法及可选参数\n    ```go\n    // 方法定义\n    // text：markdown格式字符串\n    SendMarkDownMessage(title, text string, opts ...atOption) error\n    \n    // 可选参数 目前钉钉markdown格式消息不支持@（可能是钉钉的bug），所以以下可选参数暂时不生效。\n    // @所有人\n    WithAtAll()\n    \n    // @指定群成员\n    WithAtMobiles(mobiles []string)\n    ```\n- 使用\n    ```go\n    cli.SendMarkDownMessage(title, text)\n    ```\n- Markdown进阶\n    ```go\n    // 按行写入数组，增强markdown的可读性\n    msg := []string{\n        \"### Link test\",\n        \"---\",\n        \"- \u003cfont color=#00ff00 size=6\u003e红色文字\u003c/font\u003e\",\n        \"- content2\",\n    }\n    cli.SendMarkDownMessageBySlice(\"Markdown title\", msg, WithAtAll())\n  \n    // 字体及颜色\n    dm := DingMap()\n    dm.Set(\"颜色测试\", H2)\n    dm.Set(\"失败：$$ 同行不同色 $$\", RED)  // 双$分隔\n    dm.Set(\"---\", N)\n    dm.Set(\"金色\", GOLD)\n    dm.Set(\"成功\", GREEN)\n    dm.Set(\"警告\", BLUE)\n    dm.Set(\"普通文字\", N)\n    cli.SendMarkDownMessageBySlice(\"color test\", dm.Slice())\n    ```\n- ![Xnip2020-07-05_10-27-33.jpg](https://i.loli.net/2020/07/05/7LScefCZIGnDjBV.jpg)\n- ![Xnip2020-07-26_17-14-40.jpg](https://i.loli.net/2020/07/26/PADJ5uqmfQht2cr.jpg)\n\n- 点击DTMD链接发送消息\n\n    点击'dtmdLink1'，自动发送'dtmdValue1'并@机器人，简化输入\n    ```go\n    // 创建有序map\n    dtmdOrderMap := DingMap().\n        Set(\"dtmdOrderMap1\", \"dtmdValue1\").\n        Set(\"dtmdOrderMap2\", \"dtmdValue2\").\n        Set(\"dtmdOrderMap3\", \"dtmdValue3\")\n    err := dingTalkCli.SendDTMDMessage(\"DTMD title\", dtmdOrderMap)\n    ```\n- ![Xnip2020-11-02_17-17-26.jpg](https://i.loli.net/2020/11/02/1OqEr4HKZWapRgd.jpg)\n\n### 整体跳转ActionCard类型\n- 方法及可选参数\n    ```go\n    // 方法定义\n    SendActionCardMessage(title, text string, opts ...actionCardOption) error\n    \n    // 可选参数\n    // 标题\n    WithCardSingleTitle(title string)\n    \n    // 跳转地址\n    WithCardSingleURL(url string)\n    ```\n- 使用\n    ```go\n    cli.SendActionSingleMessage(title, text, WithCardSingleTitle(sTitle), WithCardSingleURL(url))\n    ```\n- ![Xnip2020-07-05_10-28-57.jpg](https://i.loli.net/2020/07/05/kKELHAlomndiO9I.jpg)\n\n### 独立跳转ActionCard类型\n- 方法及可选参数\n    ```go\n    // 方法定义\n    SendActionCardMessage(title, text string, opts ...actionCardOption) error\n    \n    // 可选参数\n    // 按钮排列方向，默认水平\n    WithCardBtnVertical()\n  \n    // 跳转按钮\n    WithCardBtns(btns []ActionCardMultiBtnModel)\n\n    // ActionCardMultiBtnModel\n    type ActionCardMultiBtnModel struct {\n    \tTitle     string `json:\"title,omitempty\"`\n    \tActionURL string `json:\"actionURL,omitempty\"`\n    }\n    ```\n- 使用\n    ```go\n    btns := []ActionCardMultiBtnModel{{\n        Title:     \"test1\",\n        ActionURL: testUrl,\n        },{\n        Title:     \"test2\",\n        ActionURL: testUrl,\n        },\n    }\n    cli.SendActionSingleMessage(title, text, WithCardBtns(btns))\n    ```\n- ![Xnip2020-07-05_10-29-21.jpg](https://i.loli.net/2020/07/05/t9GywHFSQUWCVDT.jpg)\n- ![Xnip2020-07-26_17-14-56.jpg](https://i.loli.net/2020/07/26/pEg7hotXZnsaJPV.jpg)\n\n### FeedCard类型\n- 方法\n    ```go\n    // 方法定义\n    SendFeedCardMessage(feedCard []FeedCardLinkModel) error\n    \n    // FeedCardLinkModel\n    type FeedCardLinkModel struct {\n    \tTitle      string `json:\"title,omitempty\"`\n    \tMessageURL string `json:\"messageURL,omitempty\"`\n    \tPicURL     string `json:\"picURL,omitempty\"`\n    }\n    ```\n- 使用\n    ```go\n    links := []FeedCardLinkModel{\n        {\n            Title:      \"FeedCard1.\",\n            MessageURL: testUrl,\n            PicURL:     testImg,\n        },\n        {\n            Title:      \"FeedCard2\",\n            MessageURL: testUrl,\n            PicURL:     testImg,\n        },\n        {\n            Title:      \"FeedCard3\",\n            MessageURL: testUrl,\n            PicURL:     testImg,\n        },\n    }\n    cli.SendFeedCardMessage(links)\n    ```\n- ![Xnip2020-07-05_10-30-02.jpg](https://i.loli.net/2020/07/05/F5WDLqyJ4Yzfj6A.jpg)","funding_links":[],"categories":["Go","开发库和SDK"],"sub_categories":["Golang"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblinkbean%2Fdingtalk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblinkbean%2Fdingtalk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblinkbean%2Fdingtalk/lists"}