diff --git a/server/notification.js b/server/notification.js
index 446753ea4..cb77a6190 100644
--- a/server/notification.js
+++ b/server/notification.js
@@ -279,6 +279,116 @@ class Notification {
                 throwGeneralAxiosError(error)
             }
 
+        } else if (notification.type === "mattermost") {
+            try {
+                const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
+                // If heartbeatJSON is null, assume we're testing.
+                if (heartbeatJSON == null) {
+                    let mattermostTestData = {
+                        username: mattermostUserName,
+                        text: msg,
+                    }
+                    await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
+                    return okMsg;
+                }
+                
+                const mattermostChannel = notification.mattermostchannel;
+                const mattermostIconEmoji = notification.mattermosticonemo;
+                const mattermostIconUrl = notification.mattermosticonurl;
+
+                if (heartbeatJSON["status"] == 0) {
+                    let mattermostdowndata = {
+                        username: mattermostUserName,
+                        text: "Uptime Kuma Alert",
+                        channel: mattermostChannel,
+                        icon_emoji: mattermostIconEmoji,
+                        icon_url: mattermostIconUrl,
+                        attachments: [
+                            {
+                                fallback:
+                                    "Your " +
+                                    monitorJSON["name"] +
+                                    " service went down.",
+                                color: "#FF0000",
+                                title:
+                                    "❌ " +
+                                    monitorJSON["name"] +
+                                    " service went down. ❌",
+                                title_link: monitorJSON["url"],
+                                fields: [
+                                    {
+                                        short: true,
+                                        title: "Service Name",
+                                        value: monitorJSON["name"],
+                                    },
+                                    {
+                                        short: true,
+                                        title: "Time (UTC)",
+                                        value: heartbeatJSON["time"],
+                                    },
+                                    {
+                                        short: false,
+                                        title: "Error",
+                                        value: heartbeatJSON["msg"],
+                                    },
+                                ],
+                            },
+                        ],
+                    };
+                    await axios.post(
+                        notification.mattermostWebhookUrl,
+                        mattermostdowndata
+                    );
+                    return okMsg;
+                } else if (heartbeatJSON["status"] == 1) {
+                    let mattermostupdata = {
+                        username: mattermostUserName,
+                        text: "Uptime Kuma Alert",
+                        channel: mattermostChannel,
+                        icon_emoji: mattermostIconEmoji,
+                        icon_url: mattermostIconUrl,
+                        attachments: [
+                            {
+                                fallback:
+                                    "Your " +
+                                    monitorJSON["name"] +
+                                    " service went up!",
+                                color: "#32CD32",
+                                title:
+                                    "✅ " +
+                                    monitorJSON["name"] +
+                                    " service went up! ✅",
+                                title_link: monitorJSON["url"],
+                                fields: [
+                                    {
+                                        short: true,
+                                        title: "Service Name",
+                                        value: monitorJSON["name"],
+                                    },
+                                    {
+                                        short: true,
+                                        title: "Time (UTC)",
+                                        value: heartbeatJSON["time"],
+                                    },
+                                    {
+                                        short: false,
+                                        title: "Ping",
+                                        value: heartbeatJSON["ping"] + "ms",
+                                    },
+                                ],
+                            },
+                        ],
+                    };
+                    await axios.post(
+                        notification.mattermostWebhookUrl,
+                        mattermostupdata
+                    );
+                    return okMsg;
+                }
+            } catch (error) {
+                throwGeneralAxiosError(error);
+            }
+
         } else if (notification.type === "pushover") {
             let pushoverlink = "https://api.pushover.net/1/messages.json"
             try {
diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue
index 43b56b2f1..d639e4f23 100644
--- a/src/components/NotificationDialog.vue
+++ b/src/components/NotificationDialog.vue
@@ -27,6 +27,7 @@
                                 <option value="apprise">Apprise (Support 50+ Notification services)</option>
                                 <option value="pushbullet">Pushbullet</option>
                                 <option value="line">Line Messenger</option>
+                                <option value="mattermost">Mattermost</option>
                             </select>
                         </div>
 
@@ -238,6 +239,39 @@
                             </div>
                         </template>
 
+                        <template v-if="notification.type === 'mattermost'">
+                            <div class="mb-3">
+                                <label for="mattermost-webhook-url" class="form-label">Webhook URL<span style="color:red;"><sup>*</sup></span></label>
+                                <input id="mattermost-webhook-url" v-model="notification.mattermostWebhookUrl" type="text" class="form-control" required>
+                                <label for="mattermost-username" class="form-label">Username</label>
+                                <input id="mattermost-username" v-model="notification.mattermostusername" type="text" class="form-control">
+                                <label for="mattermost-iconurl" class="form-label">Icon URL</label>
+                                <input id="mattermost-iconurl" v-model="notification.mattermosticonurl" type="text" class="form-control">
+                                <label for="mattermost-iconemo" class="form-label">Icon Emoji</label>
+                                <input id="mattermost-iconemo" v-model="notification.mattermosticonemo" type="text" class="form-control">
+                                <label for="mattermost-channel" class="form-label">Channel Name</label>
+                                <input id="mattermost-channel-name" v-model="notification.mattermostchannel" type="text" class="form-control">
+                                <div class="form-text">
+                                    <span style="color:red;"><sup>*</sup></span>Required
+                                    <p style="margin-top: 8px;">
+                                        More info about webhooks on: <a href="https://docs.mattermost.com/developer/webhooks-incoming.html" target="_blank">https://docs.mattermost.com/developer/webhooks-incoming.html</a>
+                                    </p>
+                                    <p style="margin-top: 8px;">
+                                        You can override the default channel that webhook posts to by entering the channel name into "Channel Name" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel
+                                    </p>
+                                    <p style="margin-top: 8px;">
+                                        If you leave the Uptime Kuma URL field blank, it will default to the Project Github page.
+                                    </p>
+                                    <p style="margin-top: 8px;">
+                                        You can provide a link to a picture in "Icon URL" to override the default profile picture. Will not be used if Icon Emoji is set.
+                                    </p>
+                                    <p style="margin-top: 8px;">
+                                        Emoji cheat sheet: <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">https://www.webfx.com/tools/emoji-cheat-sheet/</a> Note: emoji takes preference over Icon URL.
+                                    </p>
+                                </div>
+                            </div>
+                        </template>
+
                         <template v-if="notification.type === 'pushy'">
                             <div class="mb-3">
                                 <label for="pushy-app-token" class="form-label">API_KEY</label>