louislam/uptime-kuma · error · Error
SMTP connection doesn't verify: ${e}
Error message
SMTP connection doesn't verify: ${e} What it means
The SMTP monitor builds a nodemailer transport from monitor.hostname, port, and smtpSecurity mode, then calls transporter.verify() to open and authenticate a connection. Any failure (socket, TLS, auth) is caught and re-thrown as 'SMTP connection doesn\'t verify: <e>'. The original nodemailer error is interpolated, so the message after the colon carries the real cause.
Source
Thrown at server/monitor-types/smtp.js:26
/**
* @inheritdoc
*/
async check(monitor, heartbeat, _server) {
let options = {
port: monitor.port || 25,
host: monitor.hostname,
secure: monitor.smtpSecurity === "secure", // use SMTPS (not STARTTLS)
ignoreTLS: monitor.smtpSecurity === "nostarttls", // don't use STARTTLS even if it's available
requireTLS: monitor.smtpSecurity === "starttls", // use STARTTLS or fail
};
let transporter = nodemailer.createTransport(options);
try {
await transporter.verify();
heartbeat.status = UP;
heartbeat.msg = "SMTP connection verifies successfully";
} catch (e) {
throw new Error(`SMTP connection doesn't verify: ${e}`);
} finally {
transporter.close();
}
}
}
module.exports = {
SMTPMonitorType,
};
View on GitHub (pinned to 6b5ea01557)
Solutions
- Match the port to smtpSecurity: 465 for 'secure' (SMTPS), 587 for 'starttls', 25 for plain/'nostarttls'.
- Confirm outbound connectivity from the Uptime Kuma host: openssl s_client -connect host:465 or telnet host 587.
- Verify credentials and that the user is permitted to relay/auth.
- If STARTTLS is required, ensure the server advertises it and the cert is valid.
Example fix
// before monitor.smtpSecurity = 'secure'; // but port 587 // after monitor.smtpSecurity = 'starttls'; // matches port 587
Defensive patterns
Strategy: try-catch
Validate before calling
const net = require('net');
function preflightSmtp(host, port, security) {
// sanity: port matches declared security mode
const ok = (security === 'secure' && port === 465) ||
(security === 'starttls' && port === 587) ||
(security === 'nostarttls' && port === 25);
if (!ok) console.warn(`Port ${port} may not match SMTP security mode '${security}'`);
} Type guard
function isSmtpPortModeMatch(port, security) {
return (security === 'secure' && port === 465) ||
(security === 'starttls' && port === 587) ||
(security === 'nostarttls' && port === 25);
} Try / catch
try {
await smtpMonitor.check(monitor, heartbeat, server);
} catch (e) {
if (/doesn't verify/.test(e.message)) {
// inner cause is after the colon: GREETING/EAUTH/ECONNECTION/EENVELOPE
heartbeat.status = DOWN;
heartbeat.msg = e.message;
}
} Prevention
- Match port to security mode (465/SMTPS, 587/STARTTLS, 25/plain).
- Verify outbound 25/465/587 are not blocked by the hoster.
- Use valid credentials and confirm the user is permitted to authenticate.
When it happens
Trigger: transporter.verify() rejects: host unreachable, connection refused, TLS handshake failure, STARTTLS required but unavailable, or authentication error. The finally block still calls transporter.close().
Common situations: Wrong port (25/465/587 mismatch with smtpSecurity), secure vs STARTTLS mismatch, firewall blocking outbound SMTP, credentials wrong, or host doing opportunistic TLS that fails.
Related errors
- TLS Connection failed: ${message}
- Expected TLS alert '${expectedTlsAlert}' but got unexpected
- ${message}
- Unexpected status code: ${result.status}
- Invalid Docker response, is it Docker really a daemon?
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/32eb11b32a2358a5.
Report an issue: GitHub.