本文档对自定义钉钉机器人的流程与注意事项做一个简单介绍,没有知识点,作为一个日常笔记,储备一些小工具。
一、获取自定义机器人webhook
步骤一、打开机器人管理页面
- 以PC端为例,打开PC端钉钉,点击头像,选择“机器人管理”。

步骤二、在机器人管理页面选择“自定义”机器人
- 输入机器人名字并选择要发送消息的群,同时可以为机器人设置机器人头像。

步骤三、完成必要的安全设置
- 安全设置至少选择一种,勾选我已阅读并同意《自定义机器人服务及免责条款》,点击“完成”。安全设置目前有3种方式,设置说明见下文介绍。
*这种安全设置是后来添加的 之前是没有安全验证

步骤四、复制出机器人的Webhook地址
1
|
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX
|
注意:请保管好此Webhook 地址,不要公布在外部网站上,泄露后有安全风险。
二、安全设置
安全设置目前有3种方式:
方式一、自定义关键词
最多可以设置10个关键词,消息中至少包含其中1个关键词才可以发送成功。
例如:添加了一个自定义关键词:监控报警
则这个机器人所发送的消息,必须包含 监控报警 这个词,才能发送成功。

- 代码实现 由于在自定义关键词上关键词是业务报警 所以发送的消息里一定要有这几个字才能发送成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
from urllib import parse, request
import json
import time
import hmac
import hashlib
import base64
import urllib.parse
def ding_api(contents):
url = "https://oapi.dingtalk.com/robot/send?access_token=67f7dbda6efff871c39005b0ee812d89d64887180b40d0dbdcb87daca2022817"
data={
"msgtype": "markdown",
"markdown": {
"title":"北京天气",
"text": "#### 杭州天气 ####@17600XXXXX \n> 9度,西北风1级,空气良89,相对温度73%\n> \n> ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"
},
"at": {
"atMobiles": [
"17600XXXXX"
],
"isAtAll": False
}
}
postdata = json.dumps(data).encode('utf-8')
req = request.Request(url=url, data=postdata)
req.add_header('Content-Type', 'application/json')
r = request.urlopen(req)
r_data = r.read().decode('utf-8')
return r_data
if __name__ == "__main__":
a = ding_api("业务报警")
print(a)
|
方式二、加签
- 第一步,把timestamp+”\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)。
参数 |
说明 |
timestamp |
当前时间戳,单位是毫秒,与请求调用时间误差不能超过1小时 |
secret |
密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 |
签名计算代码示例(Python 3.8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#python 3.8
import time
import hmac
import hashlib
import base64
import urllib.parse
timestamp = str(round(time.time() * 1000))
secret = 'this is secret'
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
|
- 注意secret

- 第二步、把 timestamp和第一步得到的签名值拼接到URL中。
参数 |
说明 |
timestamp |
第一步使用到的时间戳 |
sign |
第一步得到的签名值 |
1
2
|
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×tamp=XXX&sign=XXX
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
from urllib import parse, request
import json
import time
import hmac
import hashlib
import base64
import urllib.parse
def get_sss():
timestamp = str(round(time.time() * 1000))
secret = 'SEC051d514ef45a08a377d606ef5c470a801df0ae1a9d7a2d248f2bfb166ce3de633b'
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
return timestamp,sign
def ding_api(contents):
timestamp,sign = get_sss()
url = "https://oapi.dingtalk.com/robot/send?access_token=67f7dbda6efff871c39005b0ee812d89d64887180b40d0dbdcb87daca2022817×tamp="+timestamp+"&sign="+sign
data={
"msgtype": "markdown",
"markdown": {
"title":"北京天气",
"text": "#### 杭州天气 ####@17600XXXXX \n> 9度,西北风1级,空气良89,相对温度73%\n> \n> ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"
},
"at": {
"atMobiles": [
"17600XXXXX"
],
"isAtAll": False
}
}
postdata = json.dumps(data).encode('utf-8')
req = request.Request(url=url, data=postdata)
req.add_header('Content-Type', 'application/json')
r = request.urlopen(req)
r_data = r.read().decode('utf-8')
return r_data
if __name__ == "__main__":
a = ding_api("北京天气")
print(a)
|
方式三、IP地址(段)
设定后,只有来自IP地址范围内的请求才会被正常处理。支持两种设置方式:IP、IP段,暂不支持IPv6地址白名单,格式如下:
代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
from urllib import parse, request
import json
import time
import hmac
import hashlib
import base64
import urllib.parse
def ding_api(contents):
url = "https://oapi.dingtalk.com/robot/send?access_token=67f7dbda6efff871c39005b0ee812d89d64887180b40d0dbdcb87daca2022817"
data={
"msgtype": "markdown",
"markdown": {
"title":"北京天气",
"text": "#### 北京天气 ####@17600XXXXX \n> 9度,西北风1级,空气良89,相对温度73%\n> \n> ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"
},
"at": {
"atMobiles": [
"17600XXXXX"
],
"isAtAll": False
}
}
postdata = json.dumps(data).encode('utf-8')
req = request.Request(url=url, data=postdata)
req.add_header('Content-Type', 'application/json')
r = request.urlopen(req)
r_data = r.read().decode('utf-8')
return r_data
if __name__ == "__main__":
a = ding_api("业务报警")
print(a)
|
- 注意:
1.个人感觉使用第二种与第三种方式可以实现配置化钉钉预警的实现,安全性也更好;
2.安全设置的上述三种方式,需要至少设置其中一种,以进行安全保护。校验不通过的消息将会发送失败,错误如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 消息内容中不包含任何关键词
{
"errcode":310000,
"errmsg":"keywords not in content"
}
// timestamp 无效
{
"errcode":310000,
"errmsg":"invalid timestamp"
}
// 签名不匹配
{
"errcode":310000,
"errmsg":"sign not match"
}
// IP地址不在白名单
{
"errcode":310000,
"errmsg":"ip X.X.X.X not in whitelist"
}
|
- 使用
(1)获取到Webhook地址后,用户可以向这个地址发起HTTP POST 请求,即可实现给该钉钉群发送消息。注意,发起POST请求时,必须将字符集编码设置成UTF-8。
(2)当前自定义机器人支持文本 (text)、链接 (link)、markdown(markdown)、ActionCard、FeedCard消息类型,大家可以根据自己的使用场景选择合适的消息类型,达到最好的展示样式。
(3)自定义机器人发送消息时,可以通过手机号码指定“被@人列表”。在“被@人列表”里面的人员收到该消息时,会有@消息提醒(免打扰会话仍然通知提醒,首屏出现“有人@你”)。
(4)当前机器人尚不支持应答机制 (该机制指的是群里成员在聊天@机器人的时候,钉钉回调指定的服务地址,即Outgoing机器人)。