Skip to content

V1 API 文档

V1 API 提供基于任务的消息推送接口,支持多渠道、多格式发送。

💡 推荐使用 V2 API(模板)

对于所有新项目,我们强烈推荐使用 V2 API(模板)

  • 内容复用 - 模板可以在多个场景中复用,无需每次传递完整内容
  • 完全动态 - 通过占位符可以实现完全动态内容(甚至可以只用一个占位符)
  • 统一管理 - 在管理后台统一管理消息模板,便于维护
  • 版本控制 - 模板内容修改不影响 API 调用代码
  • 更安全 - 使用加密 Token,不暴露模板 ID

关于 V1 API

V1 API 仅为兼容历史数据而保留,不推荐在新项目中使用。后续的功能优化和维护重点都在 V2 API(模板)上。

接口地址

POST /api/v1/message/send

请求参数

基本参数

参数类型必填说明
tokenstring推送令牌(加密),在管理后台查看
task_idstring任务ID(明文),与 token 二选一
titlestring消息标题
textstring纯文本格式内容
htmlstringHTML 格式内容
markdownstringMarkdown 格式内容

提示

  • tokentask_id 二选一,推荐使用加密的 token
  • texthtmlmarkdown 至少提供一种格式
  • 多种格式可以同时提供,系统会根据渠道自动选择

@提醒参数(可选)

参数类型必填说明
at_mobilesarray@手机号列表,如 ["13800138000", "13900139000"]
at_useridsarray@用户ID列表,如 ["user001", "user002"]
at_allboolean是否@所有人,默认 false

注意

@提醒功能仅在支持的渠道(钉钉、企业微信)中生效。

动态接收者参数(可选)🆕

参数类型必填说明
recipientsarray动态接收者列表,如 ["user1@example.com", "user2@example.com"]

群发模式

动态接收者功能允许在 API 调用时指定接收者列表,实现群发功能。

支持的渠道:

  • 邮件 - 支持多个收件人,实现邮件群发
  • 微信公众号 - 支持多个 OpenID,实现公众号群发

使用条件:

  1. 任务实例必须配置为"动态接收者模式"
  2. 一个任务只能配置一个动态接收实例
  3. 动态接收实例不能与固定接收实例混合使用

配置方式: 在任务编辑页面,添加实例时勾选"动态接收者模式",此时无需配置固定接收者。

注意事项:

  • 如果任务配置了动态接收实例,recipients 参数为必填
  • 不支持动态接收的渠道会忽略此参数
  • 建议控制接收者数量,避免触发渠道限流

请求示例

基本示例(纯文本)

json
{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "系统通知",
    "text": "Hello World!"
}

多格式示例

json
{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "系统通知",
    "text": "您好,系统检测到异常登录。",
    "html": "<h2>系统通知</h2><p>您好,系统检测到<strong>异常登录</strong>。</p>",
    "markdown": "## 系统通知\n\n您好,系统检测到**异常登录**。"
}

带@提醒示例

json
{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "紧急告警",
    "text": "服务器CPU使用率超过90%,请及时处理!",
    "markdown": "## 紧急告警\n\n服务器CPU使用率超过**90%**,请及时处理!",
    "at_mobiles": ["13800138000", "13900139000"],
    "at_all": false
}

动态接收者示例(群发)🆕

json
{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "系统维护通知",
    "text": "系统将于今晚22:00进行维护,预计持续2小时。",
    "html": "<h2>系统维护通知</h2><p>系统将于今晚<strong>22:00</strong>进行维护,预计持续<strong>2小时</strong>。</p>",
    "recipients": [
        "user1@example.com",
        "user2@example.com",
        "user3@example.com"
    ]
}

cURL 示例

bash
curl -X POST http://your-domain/api/v1/message/send \
  -H "Content-Type: application/json" \
  -d '{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "系统通知",
    "text": "Hello World!"
  }'

响应格式

成功响应

json
{
    "code": 200,
    "msg": "success",
    "data": {
        "status": "sent"
    }
}

失败响应

json
{
    "code": 400,
    "msg": "error message",
    "data": null
}

获取 Token

  1. 登录 Message Nest 管理后台
  2. 进入"发送任务"页面
  3. 创建新的发送任务
  4. 配置推送渠道(邮件、钉钉、企业微信等)
  5. 保存后获得推送令牌(Token)

消息格式优先级

V1 API 支持三种消息格式,系统会根据任务实例配置的格式类型自动选择对应的内容。

格式选择规则

当任务实例配置了特定格式类型时,系统按以下优先级选择内容:

实例配置格式优先级顺序说明
HTMLhtml → markdown → text优先使用 HTML,其次 Markdown,最后纯文本
Markdownmarkdown → text → html优先使用 Markdown,其次纯文本,最后 HTML
Texttext → markdown → html优先使用纯文本,其次 Markdown,最后 HTML

示例说明

场景 1:邮件渠道(配置为 HTML 格式)

json
{
  "text": "纯文本内容",
  "html": "<h1>HTML内容</h1>",
  "markdown": "# Markdown内容"
}

发送结果:使用 html 内容

场景 2:钉钉渠道(配置为 Markdown 格式)

json
{
  "text": "纯文本内容",
  "markdown": "# Markdown内容"
}

发送结果:使用 markdown 内容

场景 3:只提供纯文本

json
{
  "text": "纯文本内容"
}

发送结果:所有渠道都使用 text 内容(兼容性最好)

最佳实践

  • 邮件渠道:推荐提供 html 格式,视觉效果更好
  • 钉钉/企业微信:推荐提供 markdown 格式,支持富文本
  • 通用场景:至少提供 text 格式,确保所有渠道都能正常发送
  • 多渠道任务:同时提供多种格式,让系统自动选择最佳格式

@提醒功能

@提醒功能允许在钉钉、企业微信等支持的渠道中@特定用户或所有人。

支持的渠道

渠道@手机号@用户ID@所有人
钉钉
企业微信
邮件
其他

使用示例

@指定手机号

json
{
  "token": "...",
  "title": "系统告警",
  "text": "服务器异常,请及时处理",
  "at_mobiles": ["13800138000", "13900139000"]
}

@指定用户ID

json
{
  "token": "...",
  "title": "任务通知",
  "text": "您的任务已完成",
  "at_userids": ["user001", "user002"]
}

@所有人

json
{
  "token": "...",
  "title": "重要通知",
  "text": "系统将于今晚22:00进行维护",
  "at_all": true
}

组合使用

json
{
  "token": "...",
  "title": "紧急告警",
  "markdown": "## 紧急告警\n\n生产环境出现严重问题!",
  "at_mobiles": ["13800138000"],
  "at_userids": ["admin"],
  "at_all": false
}

注意事项

  1. @提醒只在支持的渠道中生效,其他渠道会忽略这些参数
  2. 钉钉机器人需要配置相应的权限才能使用@功能
  3. @所有人功能需谨慎使用,避免打扰群成员
  4. 手机号和用户ID格式需符合对应平台的要求

支持的推送渠道

渠道支持格式@提醒动态接收者说明
邮件Text, HTMLSMTP邮件发送,支持群发多个收件人
钉钉Text, Markdown钉钉机器人,支持 Markdown 富文本
企业微信Text, Markdown企业微信机器人,支持 Markdown
微信公众号Text微信测试公众号,支持多个 OpenID 群发
自定义WebhookText, HTML, Markdown自定义HTTP请求,格式取决于配置
自托管消息Text, HTML, Markdown站内消息,支持多种格式

使用流程

  1. 创建推送渠道

    • 在管理后台配置各种推送渠道
    • 填写相应的配置信息(如邮箱、Webhook地址等)
  2. 创建发送任务

    • 选择要使用的推送渠道
    • 可以选择多个渠道同时推送
    • 获得唯一的推送令牌(Token)
  3. 调用API发送消息

    • 使用获得的 Token
    • 发送标题和内容
    • 消息会自动推送到配置的所有渠道

工作流程

  1. Token 解析 - 解密 Token 获取任务 ID(或直接使用 task_id)
  2. 任务查询 - 根据任务 ID 查询任务信息
  3. 实例遍历 - 获取任务关联的所有启用实例
  4. 格式选择 - 根据实例配置的格式类型选择对应内容
  5. @提醒处理 - 如果提供了@参数且渠道支持,添加@提醒
  6. 消息发送 - 向每个实例发送消息
  7. 返回结果 - 返回发送状态

注意事项

重要

  • Token 安全:Token 是唯一的,请妥善保管,不要在公开代码中硬编码
  • 格式兼容:至少提供一种格式(text/html/markdown),推荐提供多种格式
  • 异步调用:建议使用异步方式调用 API,避免阻塞主流程
  • @提醒限制:@功能仅在钉钉、企业微信等支持的渠道中生效
  • 格式优先级:系统会根据实例配置自动选择最合适的格式

最佳实践

1. 多格式支持

为了确保消息在不同渠道都有良好的展示效果,建议同时提供多种格式:

json
{
  "token": "...",
  "title": "订单通知",
  "text": "您的订单已发货,订单号:20241206001",
  "html": "<h2>订单通知</h2><p>您的订单已发货</p><p>订单号:<strong>20241206001</strong></p>",
  "markdown": "## 订单通知\n\n您的订单已发货\n\n订单号:**20241206001**"
}

2. 合理使用@提醒

只在需要紧急通知时使用@提醒:

json
{
  "token": "...",
  "title": "紧急告警",
  "text": "生产环境出现严重问题",
  "at_mobiles": ["13800138000"],  // 只@相关负责人
  "at_all": false  // 避免@所有人
}

3. 错误处理

python
import requests
import json

def send_message(token, title, text):
    url = "http://your-domain/api/v1/message/send"
    data = {
        "token": token,
        "title": title,
        "text": text
    }
    
    try:
        response = requests.post(url, json=data, timeout=10)
        result = response.json()
        
        if result['code'] == 200:
            print("发送成功")
        else:
            print(f"发送失败:{result['msg']}")
    except Exception as e:
        print(f"请求异常:{e}")

错误码说明

错误码说明
200成功
400请求参数错误
401未授权
404Token不存在
500服务器内部错误

常见问题

Q: V1 和 V2 API 有什么区别?应该选择哪个?

A:

特性V1 API(任务)V2 API(模板)⭐ 推荐
内容定义API 调用时传递预定义在模板中
动态内容完全动态通过占位符替换
内容复用每次都要传递完整内容模板可复用
维护成本修改内容需要改代码只需修改模板
适用场景完全动态、不重复的内容有固定格式的通知消息

推荐使用 V2 API(模板)的原因:

  1. 提高开发效率 - 一次定义模板,多处使用
  2. 降低维护成本 - 内容修改无需改代码
  3. 统一管理 - 所有消息模板集中管理
  4. 更好的协作 - 运营人员可以直接修改模板内容
  5. 版本控制 - 模板支持启用/禁用,方便灰度发布
  6. 完全动态 - 通过占位符同样可以实现完全动态内容

V1 API 的定位

V1 API 仅为兼容历史数据而保留,不推荐在任何新项目中使用。即使是完全动态的内容,也可以通过模板 + 占位符的方式实现,且更易于后期维护。

后续的功能优化和维护重点都在 V2 API(模板)上。

Q: 如何选择使用哪种格式?

A: 根据渠道特性选择:

  • 邮件:推荐 HTML,视觉效果好
  • 钉钉/企业微信:推荐 Markdown,支持富文本
  • 通用:使用 Text,兼容性最好
  • 多渠道:同时提供多种格式,让系统自动选择

Q: @提醒不生效怎么办?

A: 检查以下几点:

  1. 渠道是否支持@提醒(仅钉钉、企业微信支持)
  2. 机器人是否有@权限
  3. 手机号或用户ID格式是否正确
  4. 参数名称是否正确(at_mobilesat_useridsat_all

Q: 可以只发送 HTML 格式吗?

A: 可以,但建议同时提供 text 格式作为备选,确保不支持 HTML 的渠道也能正常发送。

Q: Token 和 task_id 有什么区别?

A:

  • token:加密的任务标识,更安全,推荐使用
  • task_id:明文的任务ID,不推荐在生产环境使用

各语言调用示例

本节提供各种编程语言的完整调用示例代码。

cURL

bash
curl -X POST --location 'http://127.0.0.1:8000/api/v1/message/send' \
  --header 'Content-Type: application/json' \
  --data '{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "message title",
    "text": "Hello World!"
  }'

Python

python
import requests

headers = {
    'Content-Type': 'application/json',
}

json_data = {
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "message title",
    "text": "Hello World!"
}

response = requests.post(
    'http://127.0.0.1:8000/api/v1/message/send',
    headers=headers,
    json=json_data
)

print("response:", response.json())

安装依赖:

bash
pip install requests

Go

go
package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
)

func main() {
	client := &http.Client{}
	var data = strings.NewReader(`{
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "message title",
    "text": "Hello World!"
}`)
	req, err := http.NewRequest("POST", "http://127.0.0.1:8000/api/v1/message/send", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", bodyText)
}

Java

java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;

public class MessageNestExample {
    public static void main(String[] args) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newBuilder()
            .followRedirects(HttpClient.Redirect.NORMAL)
            .build();

        String jsonData = """
            {
                "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
                "title": "message title",
                "text": "Hello World!"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://127.0.0.1:8000/api/v1/message/send"))
            .POST(BodyPublishers.ofString(jsonData))
            .setHeader("Content-Type", "application/json")
            .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        
        System.out.println(response.body());
    }
}

Node.js

使用 request 库

javascript
var request = require('request');

var headers = {
    'Content-Type': 'application/json'
};

var dataString = JSON.stringify({
    "token": "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title": "message title",
    "text": "Hello World!"
});

var options = {
    url: 'http://127.0.0.1:8000/api/v1/message/send',
    method: 'POST',
    headers: headers,
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);

使用 axios 库

javascript
const axios = require('axios');

const data = {
    token: "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    title: "message title",
    text: "Hello World!"
};

axios.post('http://127.0.0.1:8000/api/v1/message/send', data, {
    headers: {
        'Content-Type': 'application/json'
    }
})
.then(response => {
    console.log('response:', response.data);
})
.catch(error => {
    console.error('error:', error);
});

使用 fetch (Node.js 18+)

javascript
const data = {
    token: "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    title: "message title",
    text: "Hello World!"
};

fetch('http://127.0.0.1:8000/api/v1/message/send', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
    console.log('response:', data);
})
.catch(error => {
    console.error('error:', error);
});

PHP

php
<?php
$ch = curl_init();

$data = array(
    "token" => "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
    "title" => "message title",
    "text" => "Hello World!"
);

curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:8000/api/v1/message/send');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
} else {
    echo $response;
}

curl_close($ch);
?>

C#

csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        using var client = new HttpClient();
        
        var data = new
        {
            token = "a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e",
            title = "message title",
            text = "Hello World!"
        };
        
        var json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        
        var response = await client.PostAsync(
            "http://127.0.0.1:8000/api/v1/message/send",
            content
        );
        
        var responseString = await response.Content.ReadAsStringAsync();
        Console.WriteLine(responseString);
    }
}

Ruby

ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI('http://127.0.0.1:8000/api/v1/message/send')
http = Net::HTTP.new(uri.host, uri.port)

request = Net::HTTP::Post.new(uri.path, {
  'Content-Type' => 'application/json'
})

request.body = {
  token: 'a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e',
  title: 'message title',
  text: 'Hello World!'
}.to_json

response = http.request(request)
puts response.body

示例说明

提示

  • 将示例中的 http://127.0.0.1:8000 替换为你的实际服务地址
  • a3541c2f0d3e1b4a5c6d7e8f9a0b1c2d3e 替换为你在管理后台创建的实际 Token
  • 建议在生产环境中使用 HTTPS
  • 所有示例都使用基本的纯文本格式,实际使用时可以添加 htmlmarkdown 等参数

下一步

Released under the MIT License.