diff --git a/server/notification-providers/aliyun-sms.js b/server/notification-providers/aliyun-sms.js
new file mode 100644
index 000000000..6a2063200
--- /dev/null
+++ b/server/notification-providers/aliyun-sms.js
@@ -0,0 +1,108 @@
+const NotificationProvider = require("./notification-provider");
+const { DOWN, UP } = require("../../src/util");
+const { default: axios } = require("axios");
+const Crypto = require("crypto");
+const qs = require("qs");
+
+class AliyunSMS extends NotificationProvider {
+ name = "AliyunSMS";
+
+ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
+ let okMsg = "Sent Successfully.";
+
+ try {
+ if (heartbeatJSON != null) {
+ let msgBody = JSON.stringify({
+ name: monitorJSON["name"],
+ time: heartbeatJSON["time"],
+ status: this.statusToString(heartbeatJSON["status"]),
+ msg: heartbeatJSON["msg"],
+ });
+ if (this.sendSms(notification, msgBody)) {
+ return okMsg;
+ }
+ } else {
+ let msgBody = JSON.stringify({
+ name: "",
+ time: "",
+ status: "",
+ msg: msg,
+ });
+ if (this.sendSms(notification, msgBody)) {
+ return okMsg;
+ }
+ }
+ } catch (error) {
+ this.throwGeneralAxiosError(error);
+ }
+ }
+
+ async sendSms(notification, msgbody) {
+ let params = {
+ PhoneNumbers: notification.phonenumber,
+ TemplateCode: notification.templateCode,
+ SignName: notification.signName,
+ TemplateParam: msgbody,
+ AccessKeyId: notification.accessKeyId,
+ Format: "JSON",
+ SignatureMethod: "HMAC-SHA1",
+ SignatureVersion: "1.0",
+ SignatureNonce: Math.random().toString(),
+ Timestamp: new Date().toISOString(),
+ Action: "SendSms",
+ Version: "2017-05-25",
+ };
+
+ params.Signature = this.sign(params, notification.secretAccessKey);
+ let config = {
+ method: "POST",
+ url: "http://dysmsapi.aliyuncs.com/",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ data: qs.stringify(params),
+ };
+
+ let result = await axios(config);
+ if (result.data.Message == "OK") {
+ return true;
+ }
+ return false;
+ }
+
+ /** Aliyun request sign */
+ sign(param, AccessKeySecret) {
+ let param2 = {};
+ let data = [];
+
+ let oa = Object.keys(param).sort();
+
+ for (let i = 0; i < oa.length; i++) {
+ let key = oa[i];
+ param2[key] = param[key];
+ }
+
+ for (let key in param2) {
+ data.push(`${encodeURIComponent(key)}=${encodeURIComponent(param2[key])}`);
+ }
+
+ let StringToSign = `POST&${encodeURIComponent("/")}&${encodeURIComponent(data.join("&"))}`;
+ return Crypto
+ .createHmac("sha1", `${AccessKeySecret}&`)
+ .update(Buffer.from(StringToSign))
+ .digest("base64");
+ }
+
+ statusToString(status) {
+ switch (status) {
+ case DOWN:
+ return "DOWN";
+ case UP:
+ return "UP";
+ default:
+ return status;
+ }
+ }
+}
+
+module.exports = AliyunSMS;
diff --git a/server/notification-providers/dingding.js b/server/notification-providers/dingding.js
new file mode 100644
index 000000000..f099192d8
--- /dev/null
+++ b/server/notification-providers/dingding.js
@@ -0,0 +1,79 @@
+const NotificationProvider = require("./notification-provider");
+const { DOWN, UP } = require("../../src/util");
+const { default: axios } = require("axios");
+const Crypto = require("crypto");
+
+class DingDing extends NotificationProvider {
+ name = "DingDing";
+
+ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
+ let okMsg = "Sent Successfully.";
+
+ try {
+ if (heartbeatJSON != null) {
+ let params = {
+ msgtype: "markdown",
+ markdown: {
+ title: monitorJSON["name"],
+ text: `## [${this.statusToString(heartbeatJSON["status"])}] \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`,
+ }
+ };
+ if (this.sendToDingDing(notification, params)) {
+ return okMsg;
+ }
+ } else {
+ let params = {
+ msgtype: "text",
+ text: {
+ content: msg
+ }
+ };
+ if (this.sendToDingDing(notification, params)) {
+ return okMsg;
+ }
+ }
+ } catch (error) {
+ this.throwGeneralAxiosError(error);
+ }
+ }
+
+ async sendToDingDing(notification, params) {
+ let timestamp = Date.now();
+
+ let config = {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ url: `${notification.webHookUrl}×tamp=${timestamp}&sign=${encodeURIComponent(this.sign(timestamp, notification.secretKey))}`,
+ data: JSON.stringify(params),
+ };
+
+ let result = await axios(config);
+ if (result.data.errmsg == "ok") {
+ return true;
+ }
+ return false;
+ }
+
+ /** DingDing sign */
+ sign(timestamp, secretKey) {
+ return Crypto
+ .createHmac("sha256", Buffer.from(secretKey, "utf8"))
+ .update(Buffer.from(`${timestamp}\n${secretKey}`, "utf8"))
+ .digest("base64");
+ }
+
+ statusToString(status) {
+ switch (status) {
+ case DOWN:
+ return "DOWN";
+ case UP:
+ return "UP";
+ default:
+ return status;
+ }
+ }
+}
+
+module.exports = DingDing;
diff --git a/server/notification.js b/server/notification.js
index 41a0063c3..658216f91 100644
--- a/server/notification.js
+++ b/server/notification.js
@@ -19,6 +19,8 @@ const Teams = require("./notification-providers/teams");
const Telegram = require("./notification-providers/telegram");
const Webhook = require("./notification-providers/webhook");
const Feishu = require("./notification-providers/feishu");
+const AliyunSms = require("./notification-providers/aliyun-sms");
+const DingDing = require("./notification-providers/dingding");
class Notification {
@@ -31,6 +33,8 @@ class Notification {
const list = [
new Apprise(),
+ new AliyunSms(),
+ new DingDing(),
new Discord(),
new Teams(),
new Gotify(),
diff --git a/src/components/notifications/AliyunSms.vue b/src/components/notifications/AliyunSms.vue
new file mode 100644
index 000000000..2c25a3a9c
--- /dev/null
+++ b/src/components/notifications/AliyunSms.vue
@@ -0,0 +1,25 @@
+
+ Sms template must contain parameters: For safety, must use secret key
${name} ${time} ${status} ${msg}
*{{ $t("Required") }}