前言
想起之前有个项目需要使用钉钉消息推送报警数据到群里,提醒群里人员知道设备报警。这篇是通过C#实现钉钉消息推送,因为钉钉机器人设定需设置安全设置,有三个(自定义关键词、加签、IP地址(段)),目前是设置自定义关键词通过C#消息推送。
一、钉钉机器人如何设置
1、钉钉机器人设置需建群(在群里才能机器人)
2、点击群设置,在群管理里点击机器人管理。
3、点击添加机器人选择自定义机器人点击添加。
4、在添加钉钉机器人时需要确定加密方式有以下几种:
- 自定义关键字
- 加签
- IP地址段
注:因目前所选方式为第一种,所以需输入自定义关键字,如:"报警:"
5、点击完成后,钉钉会给出一个webhook,需复制webhook在C#中使用。
6、如果自定义机器人在群里发送招呼话语,说明已建造设置成功。
二、C#实现钉钉消息推送
1.钉钉消息类型
钉钉消息有六种消息类型,总结如下:
类型 | 是否支持交互 | 关键特性 | 适用场景 |
---|---|---|---|
文本(text) | ❌ | 纯文本,支持@成员 | 简单通知、报警 |
Markdown | ❌ | 支持Markdown格式化 | 复杂内容(如日志报告) |
链接(link) | ❌ | 标题+图片+跳转链接 | 带缩略图的通知 |
ActionCard | ✅ | 单、多 1-2个可点击按钮 | 审批、任务处理 |
FeedCard | ✅ | 多条链接列表 | 聚合通知(如新闻列表) |
2.代码实现
使用C#控制台实现钉钉机器人消息推送。
1)DingTalkRobot类型
钉钉机器人信息推送,代码如下(示例):
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
public class DingTalkRobot
{
private readonly string _webhookUrl;
private readonly HttpClient _httpClient;
public DingTalkRobot(string webhookUrl)
{
_webhookUrl = webhookUrl ?? throw new ArgumentNullException(nameof(webhookUrl));
_httpClient = new HttpClient();
}
/// <summary>
/// 发送文本消息
/// </summary>
/// <param name="content">消息内容</param>
/// <param name="atMobiles">需要@的手机号数组</param>
/// <param name="isAtAll">是否@所有人</param>
public async Task SendTextMessageAsync(string content, string[] atMobiles = null, bool isAtAll = false)
{
var message = new
{
msgtype = "text",
text = new
{
content = content
},
at = new
{
atMobiles = atMobiles ?? Array.Empty<string>(),
isAtAll = isAtAll
}
};
await SendMessageAsync(message);
}
/// <summary>
/// 发送Markdown消息
/// </summary>
/// <param name="title">标题</param>
/// <param name="text">Markdown格式内容</param>
/// <param name="atMobiles">需要@的手机号数组</param>
/// <param name="isAtAll">是否@所有人</param>
public async Task SendMarkdownMessageAsync(string title, string text, string[] atMobiles = null, bool isAtAll = false)
{
var message = new
{
msgtype = "markdown",
markdown = new
{
title = title,
text = text
},
at = new
{
atMobiles = atMobiles ?? Array.Empty<string>(),
isAtAll = isAtAll
}
};
await SendMessageAsync(message);
}
/// <summary>
/// 发送链接消息
/// </summary>
/// <param name="title">标题</param>
/// <param name="text">内容</param>
/// <param name="messageUrl">跳转链接</param>
/// <param name="picUrl">图片链接(可选)</param>
public async Task SendLinkMessageAsync(string title, string text, string messageUrl, string picUrl = "")
{
var message = new
{
msgtype = "link",
link = new
{
title = title,
text = text,
messageUrl = messageUrl,
picUrl = picUrl
}
};
await SendMessageAsync(message);
}
/// <summary>
/// 发送 单按钮 ActionCard消息
/// </summary>
/// <param name="title">消息标题,显示在消息顶部</param>
/// <param name="text">消息内容,支持Markdown语法</param>
/// <param name="singleTitle">单个按钮的文本(不超过20字符)</param>
/// <param name="singleUrl">按钮跳转链接(需HTTP/HTTPS)</param>
/// <param name="atMobiles">需要@的群成员手机号数组</param>
/// <param name="isAtAll">是否@所有人(慎用)</param>
/// <returns></returns>
public async Task SendActionCardAsync(string title, string text, string singleTitle, string singleUrl, string[] atMobiles = null, bool isAtAll = false)
{
var message = new
{
msgtype = "actionCard",
actionCard = new
{
title = title,
text = text,
singleTitle = singleTitle,
singleURL = singleUrl,
btnOrientation = "0" // "0"垂直按钮,"1"水平按钮
},
at = new
{
atMobiles = atMobiles ?? Array.Empty<string>(),
isAtAll = isAtAll
}
};
await SendMessageAsync(message);
}
/// <summary>
/// 发送 多按钮 ActionCard消息
/// </summary>
/// <param name="title">消息标题</param>
/// <param name="text">消息内容</param>
/// <param name="buttons">按钮列表(最多2个)</param>
/// <param name="btnOrientation">按钮排列方向:“0”(垂直,默认) 或 “1”(水平)</param>
/// <param name="atMobiles">需要@的手机号数组</param>
/// <param name="isAtAll">是否@所有人</param>
/// <returns></returns>
public async Task SendMultiActionCardAsync(string title, string text, List<DingTalkButton> buttons, string btnOrientation = "0", // "0"垂直,"1"水平
string[] atMobiles = null, bool isAtAll = false)
{
var message = new
{
msgtype = "actionCard",
actionCard = new
{
title = title,
text = text,
btns = buttons.Select(b => new { title = b.Title, actionURL = b.Url }).ToArray(),
btnOrientation = btnOrientation
},
at = new
{
atMobiles = atMobiles ?? Array.Empty<string>(),
isAtAll = isAtAll
}
};
await SendMessageAsync(message);
}
/// <summary>
/// 发送FeedCard消息
/// </summary>
/// <param name="links">链接列表(最多5条)</param>
/// <returns></returns>
public async Task SendFeedCardAsync(List<FeedCardLink> links)
{
var message = new
{
msgtype = "feedCard",
feedCard = new
{
links = links.Select(link => new
{
title = link.Title,
messageURL = link.MessageUrl,
picURL = link.PicUrl
}).ToArray()
}
};
await SendMessageAsync(message);
}
// FeedCard 链接定义类
public class FeedCardLink
{
//链接标题(小于等于64字符)
public string Title { get; set; }
//跳转链接(需HTTP/HTTPS)
public string MessageUrl { get; set; }
//图片链接(可选,建议尺寸:520x275像素)
public string PicUrl { get; set; }
}
// 按钮定义类
public class DingTalkButton
{
//按钮文本(小于等于20字符)
public string Title { get; set; }
//跳转链接(需HTTP/HTTPS)
public string Url { get; set; }
}
private async Task SendMessageAsync(object message)
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(message);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(_webhookUrl, content);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"钉钉机器人响应: {responseContent}");
}
}
2)Program类型
钉钉机器人发送消息实现类,代码如下:
using static DingTalkRobot;
using static System.Net.Mime.MediaTypeNames;
public class Program
{
static async Task Main(string[] args)
{
// 实际Webhook URL
var webhookUrl = "https://oapi.dingtalk.com/robot/send?access_token=ea8b2fe200c23a4ec8a9569c88ca9561d4f7ebe9bb10d1146ed07e49904c0627\r\n";
var dingTalkRobot = new DingTalkRobot(webhookUrl);
try
{
//关键字 = “报警:” 需在title、content参数加关键字
//1、发送文本消息(消息长度不超过20kb)
await dingTalkRobot.SendTextMessageAsync("报警:这是一条测试消息",
atMobiles: new[] { "13812345678" },
isAtAll: false);
//2、发送Markdown消息(1、不支持HTML和复杂表格 2、总长度不超过8192字节)
await dingTalkRobot.SendMarkdownMessageAsync(
"报警:项目更新通知",
"### 项目状态更新\n" +
"> 项目进度: 80%\n\n" +
"> 剩余时间: 2天\n\n" +
"\n" +
"###### [查看详情](https://example.com)",
atMobiles: new[] { "13812345678" });
//3、发送链接消息(最后两个 跳转链接 图片链接)
await dingTalkRobot.SendLinkMessageAsync(
"报警:系统报警通知",
"生产环境出现异常,请及时处理",
"https://www.bilibili.com/video/BV1ZU4y1q7sn/?share_source=copy_web&vd_source=ad0206b6bbe094bb6fa542017f2e474b",
"https://www.bilibili.com/opus/366829175324803541?from=search&spm_id_from=333.337.0.0");
//4、发送单按钮 ActionCard消息
await dingTalkRobot.SendActionCardAsync(
title: "报警:任务审批",
text: "**申请人**: 张三\n**内容**: 采购申请\n请及时处理!",
singleTitle: "点击审批",
singleUrl: "https://example.com/approve?id=123");
//5、发送多按钮 ActionCard消息
var buttons = new List<DingTalkButton>
{
new DingTalkButton { Title = "同意", Url = "https://example.com/agree" },
new DingTalkButton { Title = "拒绝", Url = "https://example.com/reject" }
};
await dingTalkRobot.SendMultiActionCardAsync(
title: "报警:请假审批",
text: "**员工**: 李四\n**天数**: 3天",
buttons: buttons,
btnOrientation: "1" // 水平排列按钮
);
//6、发送FeedCard消息
var links = new List<FeedCardLink>
{
new FeedCardLink
{
Title = "报警:系统报警",
MessageUrl = "https://example.com/alert1",
PicUrl = "https://example.com/alert.png"
},
new FeedCardLink
{
Title = "报警:新任务",
MessageUrl = "https://example.com/task1",
PicUrl = "https://example.com/task.png"
}
};
await dingTalkRobot.SendFeedCardAsync(links);
}
catch (Exception ex)
{
Console.WriteLine($"发送钉钉消息失败: {ex.Message}");
}
}
}
3)运行结果

