Skip to content

Commit c67f6ef

Browse files
added SMTP monitor (#5489)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
1 parent 289e824 commit c67f6ef

File tree

7 files changed

+70
-3
lines changed

7 files changed

+70
-3
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
exports.up = function (knex) {
2+
return knex.schema
3+
.alterTable("monitor", function (table) {
4+
table.string("smtp_security").defaultTo(null);
5+
});
6+
};
7+
8+
exports.down = function (knex) {
9+
return knex.schema.alterTable("monitor", function (table) {
10+
table.dropColumn("smtp_security");
11+
});
12+
};

server/model/monitor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class Monitor extends BeanModel {
153153
snmpOid: this.snmpOid,
154154
jsonPathOperator: this.jsonPathOperator,
155155
snmpVersion: this.snmpVersion,
156+
smtpSecurity: this.smtpSecurity,
156157
rabbitmqNodes: JSON.parse(this.rabbitmqNodes),
157158
conditions: JSON.parse(this.conditions),
158159
};

server/monitor-types/smtp.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const { MonitorType } = require("./monitor-type");
2+
const { UP } = require("../../src/util");
3+
const nodemailer = require("nodemailer");
4+
5+
class SMTPMonitorType extends MonitorType {
6+
name = "smtp";
7+
8+
/**
9+
* @inheritdoc
10+
*/
11+
async check(monitor, heartbeat, _server) {
12+
let options = {
13+
port: monitor.port || 25,
14+
host: monitor.hostname,
15+
secure: monitor.smtpSecurity === "secure", // use SMTPS (not STARTTLS)
16+
ignoreTLS: monitor.smtpSecurity === "nostarttls", // don't use STARTTLS even if it's available
17+
requireTLS: monitor.smtpSecurity === "starttls", // use STARTTLS or fail
18+
};
19+
let transporter = nodemailer.createTransport(options);
20+
try {
21+
await transporter.verify();
22+
23+
heartbeat.status = UP;
24+
heartbeat.msg = "SMTP connection verifies successfully";
25+
} catch (e) {
26+
throw new Error(`SMTP connection doesn't verify: ${e}`);
27+
} finally {
28+
transporter.close();
29+
}
30+
}
31+
}
32+
33+
module.exports = {
34+
SMTPMonitorType,
35+
};

server/server.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ let needSetup = false;
866866
monitor.kafkaProducerAllowAutoTopicCreation;
867867
bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly;
868868
bean.remote_browser = monitor.remote_browser;
869+
bean.smtpSecurity = monitor.smtpSecurity;
869870
bean.snmpVersion = monitor.snmpVersion;
870871
bean.snmpOid = monitor.snmpOid;
871872
bean.jsonPathOperator = monitor.jsonPathOperator;

server/uptime-kuma-server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class UptimeKumaServer {
113113
UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing();
114114
UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType();
115115
UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType();
116+
UptimeKumaServer.monitorTypeList["smtp"] = new SMTPMonitorType();
116117
UptimeKumaServer.monitorTypeList["group"] = new GroupMonitorType();
117118
UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType();
118119
UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType();
@@ -552,6 +553,7 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor
552553
const { TailscalePing } = require("./monitor-types/tailscale-ping");
553554
const { DnsMonitorType } = require("./monitor-types/dns");
554555
const { MqttMonitorType } = require("./monitor-types/mqtt");
556+
const { SMTPMonitorType } = require("./monitor-types/smtp");
555557
const { GroupMonitorType } = require("./monitor-types/group");
556558
const { SNMPMonitorType } = require("./monitor-types/snmp");
557559
const { MongodbMonitorType } = require("./monitor-types/mongodb");

src/lang/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@
10741074
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
10751075
"SendGrid API Key": "SendGrid API Key",
10761076
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas",
1077+
"smtpHelpText": "“SMTPS” tests that SMTP/TLS is working; “Ignore TLS” connects over plaintext; “STARTTLS” connects, issues a STARTTLS command and verifies the server certificate. None of these send an email.",
10771078
"Custom URL": "Custom URL",
10781079
"customUrlDescription": "Will be used as the clickable URL instead of the monitor's one.",
10791080
"OneChatAccessToken": "OneChat Access Token",

src/pages/EditMonitor.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<option value="ping">
2525
Ping
2626
</option>
27+
<option value="smtp">
28+
SMTP
29+
</option>
2730
<option value="snmp">
2831
SNMP
2932
</option>
@@ -281,8 +284,8 @@
281284
</template>
282285

283286
<!-- Hostname -->
284-
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP only -->
285-
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'snmp'" class="my-3">
287+
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP / SMTP only -->
288+
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'smtp' || monitor.type === 'snmp'" class="my-3">
286289
<label for="hostname" class="form-label">{{ $t("Hostname") }}</label>
287290
<input
288291
id="hostname"
@@ -297,7 +300,7 @@
297300

298301
<!-- Port -->
299302
<!-- For TCP Port / Steam / MQTT / Radius Type / SNMP -->
300-
<div v-if="monitor.type === 'port' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'snmp'" class="my-3">
303+
<div v-if="monitor.type === 'port' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'smtp' || monitor.type === 'snmp'" class="my-3">
301304
<label for="port" class="form-label">{{ $t("Port") }}</label>
302305
<input id="port" v-model="monitor.port" type="number" class="form-control" required min="0" max="65535" step="1">
303306
</div>
@@ -329,6 +332,18 @@
329332
</select>
330333
</div>
331334

335+
<div v-if="monitor.type === 'smtp'" class="my-3">
336+
<label for="smtp_security" class="form-label">{{ $t("SMTP Security") }}</label>
337+
<select id="smtp_security" v-model="monitor.smtpSecurity" class="form-select">
338+
<option value="secure">SMTPS</option>
339+
<option value="nostarttls">Ignore STARTTLS</option>
340+
<option value="starttls">Use STARTTLS</option>
341+
</select>
342+
<div class="form-text">
343+
{{ $t("smtpHelpText") }}
344+
</div>
345+
</div>
346+
332347
<!-- Json Query -->
333348
<!-- For Json Query / SNMP -->
334349
<div v-if="monitor.type === 'json-query' || monitor.type === 'snmp'" class="my-3">

0 commit comments

Comments
 (0)