mirror of
https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
synced 2026-04-17 17:35:59 +00:00
Improve error handling in server and client
This commit is contained in:
@@ -4,7 +4,7 @@ function togglePassword() {
|
|||||||
passInput.setAttribute('type', type);
|
passInput.setAttribute('type', type);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('smtpForm').addEventListener('submit', async function(e) {
|
document.getElementById('smtpForm').addEventListener('submit', async function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const btn = document.getElementById('testBtn');
|
const btn = document.getElementById('testBtn');
|
||||||
@@ -37,6 +37,17 @@ document.getElementById('smtpForm').addEventListener('submit', async function(e)
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
// Handle non-200 responses
|
||||||
|
const contentType = response.headers.get("content-type");
|
||||||
|
if (contentType && contentType.includes("application/json")) {
|
||||||
|
const errorResult = await response.json();
|
||||||
|
throw new Error(errorResult.message || errorResult.error || "Server Error");
|
||||||
|
} else {
|
||||||
|
const text = await response.text();
|
||||||
|
throw new Error(`Server returned ${response.status}: ${text.substring(0, 100)}...`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
@@ -48,6 +59,7 @@ document.getElementById('smtpForm').addEventListener('submit', async function(e)
|
|||||||
statusDiv.textContent = '✅ Success! Email Sent Successfully.';
|
statusDiv.textContent = '✅ Success! Email Sent Successfully.';
|
||||||
logOutput.textContent = JSON.stringify(result.details, null, 2);
|
logOutput.textContent = JSON.stringify(result.details, null, 2);
|
||||||
} else {
|
} else {
|
||||||
|
// This block handles cases where response was 200 OK but success is false (business logic error)
|
||||||
statusDiv.classList.add('status-error');
|
statusDiv.classList.add('status-error');
|
||||||
statusDiv.textContent = '❌ Error: ' + result.message;
|
statusDiv.textContent = '❌ Error: ' + result.message;
|
||||||
logOutput.textContent = result.error || 'Unknown error occurred.';
|
logOutput.textContent = result.error || 'Unknown error occurred.';
|
||||||
@@ -56,8 +68,8 @@ document.getElementById('smtpForm').addEventListener('submit', async function(e)
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
resultsDiv.classList.remove('hidden');
|
resultsDiv.classList.remove('hidden');
|
||||||
statusDiv.classList.add('status-error');
|
statusDiv.classList.add('status-error');
|
||||||
statusDiv.textContent = '❌ Network Error';
|
statusDiv.textContent = '❌ Error Caught'; // Changed from "Network Error" to be more accurate
|
||||||
logOutput.textContent = error.toString();
|
logOutput.textContent = error.message; // Use error.message instead of error.toString()
|
||||||
} finally {
|
} finally {
|
||||||
// Reset Button
|
// Reset Button
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
@@ -67,7 +79,7 @@ document.getElementById('smtpForm').addEventListener('submit', async function(e)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Auto Discovery Test Handler
|
// Auto Discovery Test Handler
|
||||||
document.getElementById('autoTestBtn').addEventListener('click', async function() {
|
document.getElementById('autoTestBtn').addEventListener('click', async function () {
|
||||||
const btn = document.getElementById('autoTestBtn');
|
const btn = document.getElementById('autoTestBtn');
|
||||||
const spinner = btn.querySelector('.loading-spinner');
|
const spinner = btn.querySelector('.loading-spinner');
|
||||||
const btnText = btn.querySelector('.btn-text');
|
const btnText = btn.querySelector('.btn-text');
|
||||||
@@ -108,6 +120,16 @@ document.getElementById('autoTestBtn').addEventListener('click', async function(
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(autoTestData),
|
body: JSON.stringify(autoTestData),
|
||||||
});
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const contentType = response.headers.get("content-type");
|
||||||
|
if (contentType && contentType.includes("application/json")) {
|
||||||
|
const errorResult = await response.json();
|
||||||
|
throw new Error(errorResult.message || errorResult.error || "Server Error");
|
||||||
|
} else {
|
||||||
|
const text = await response.text();
|
||||||
|
throw new Error(`Server returned ${response.status}: ${text.substring(0, 100)}...`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
@@ -149,8 +171,8 @@ document.getElementById('autoTestBtn').addEventListener('click', async function(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
resultsDiv.classList.remove('hidden');
|
resultsDiv.classList.remove('hidden');
|
||||||
statusDiv.classList.add('status-error');
|
statusDiv.classList.add('status-error');
|
||||||
statusDiv.textContent = '❌ Network Error';
|
statusDiv.textContent = '❌ Error Caught';
|
||||||
logOutput.textContent = error.toString();
|
logOutput.textContent = error.message;
|
||||||
} finally {
|
} finally {
|
||||||
// Reset Button
|
// Reset Button
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
|
|||||||
265
server.js
265
server.js
@@ -19,46 +19,45 @@ app.get('/', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/test-smtp', async (req, res) => {
|
app.post('/api/test-smtp', async (req, res) => {
|
||||||
const { host, port, secure, user, pass, from, to } = req.body;
|
const { host, port, secure, user, pass, from, to } = req.body;
|
||||||
|
|
||||||
// Log intent
|
// Log intent
|
||||||
console.log(
|
console.log(
|
||||||
`Attempting SMTP connection to ${host}:${port} (${
|
`Attempting SMTP connection to ${host}:${port} (${secure ? "Secure" : "Insecure"
|
||||||
secure ? "Secure" : "Insecure"
|
}) for ${user}`
|
||||||
}) for ${user}`
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// Create Transporter
|
// Create Transporter
|
||||||
const transporterConfig = {
|
const transporterConfig = {
|
||||||
host: host,
|
host: host,
|
||||||
port: parseInt(port),
|
port: parseInt(port),
|
||||||
secure: secure === true || secure === "true", // true for 465, false for other ports
|
secure: secure === true || secure === "true", // true for 465, false for other ports
|
||||||
auth: {
|
auth: {
|
||||||
user: user,
|
user: user,
|
||||||
pass: pass,
|
pass: pass,
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
// Only add TLS settings if secure is not explicitly "none"
|
|
||||||
if (secure !== "none") {
|
|
||||||
transporterConfig.tls = {
|
|
||||||
rejectUnauthorized: false, // Allow self-signed certs for testing flexibility
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport(transporterConfig);
|
// Only add TLS settings if secure is not explicitly "none"
|
||||||
|
if (secure !== "none") {
|
||||||
|
transporterConfig.tls = {
|
||||||
|
rejectUnauthorized: false, // Allow self-signed certs for testing flexibility
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Verify Connection
|
const transporter = nodemailer.createTransport(transporterConfig);
|
||||||
await transporter.verify();
|
|
||||||
console.log("SMTP Connection Verified Successfully");
|
|
||||||
|
|
||||||
// 2. Send Test Email
|
// 1. Verify Connection
|
||||||
const mailOptions = {
|
await transporter.verify();
|
||||||
from: from || user, // Default to user if from not specified
|
console.log("SMTP Connection Verified Successfully");
|
||||||
to: to,
|
|
||||||
subject: "SMTP Test - Advanced SMTP Tester",
|
// 2. Send Test Email
|
||||||
html: `
|
const mailOptions = {
|
||||||
|
from: from || user, // Default to user if from not specified
|
||||||
|
to: to,
|
||||||
|
subject: "SMTP Test - Advanced SMTP Tester",
|
||||||
|
html: `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -182,85 +181,85 @@ app.post('/api/test-smtp', async (req, res) => {
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const info = await transporter.sendMail(mailOptions);
|
const info = await transporter.sendMail(mailOptions);
|
||||||
console.log("Message sent: %s", info.messageId);
|
console.log("Message sent: %s", info.messageId);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: "Connection verified and email sent successfully!",
|
message: "Connection verified and email sent successfully!",
|
||||||
details: {
|
details: {
|
||||||
messageId: info.messageId,
|
messageId: info.messageId,
|
||||||
response: info.response,
|
response: info.response,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("SMTP Error:", error);
|
console.error("SMTP Error:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "SMTP Test Failed",
|
message: "SMTP Test Failed",
|
||||||
error: error.message,
|
error: error.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-Discovery Endpoint - Tests multiple port/encryption combinations
|
// Auto-Discovery Endpoint - Tests multiple port/encryption combinations
|
||||||
app.post('/api/auto-test-smtp', async (req, res) => {
|
app.post('/api/auto-test-smtp', async (req, res) => {
|
||||||
const { host, user, pass, from, to } = req.body;
|
const { host, user, pass, from, to } = req.body;
|
||||||
|
|
||||||
// Common SMTP port/encryption combinations to test
|
// Common SMTP port/encryption combinations to test
|
||||||
const configurations = [
|
const configurations = [
|
||||||
{ port: 587, secure: false, name: 'STARTTLS (587)', tls: true },
|
{ port: 587, secure: false, name: 'STARTTLS (587)', tls: true },
|
||||||
{ port: 465, secure: true, name: 'SSL/TLS (465)', tls: true },
|
{ port: 465, secure: true, name: 'SSL/TLS (465)', tls: true },
|
||||||
{ port: 25, secure: false, name: 'STARTTLS (25)', tls: true },
|
{ port: 25, secure: false, name: 'STARTTLS (25)', tls: true },
|
||||||
{ port: 2525, secure: false, name: 'STARTTLS (2525)', tls: true },
|
{ port: 2525, secure: false, name: 'STARTTLS (2525)', tls: true },
|
||||||
{ port: 25, secure: false, name: 'Unencrypted (25)', tls: false },
|
{ port: 25, secure: false, name: 'Unencrypted (25)', tls: false },
|
||||||
{ port: 587, secure: false, name: 'Unencrypted (587)', tls: false },
|
{ port: 587, secure: false, name: 'Unencrypted (587)', tls: false },
|
||||||
{ port: 2525, secure: false, name: 'Unencrypted (2525)', tls: false },
|
{ port: 2525, secure: false, name: 'Unencrypted (2525)', tls: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
console.log(`Starting auto-discovery for ${host} with user ${user}`);
|
console.log(`Starting auto-discovery for ${host} with user ${user}`);
|
||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
|
|
||||||
// Test each configuration
|
// Test each configuration
|
||||||
for (const config of configurations) {
|
for (const config of configurations) {
|
||||||
console.log(`Testing ${config.name}...`);
|
console.log(`Testing ${config.name}...`);
|
||||||
|
|
||||||
const transporterConfig = {
|
const transporterConfig = {
|
||||||
host: host,
|
host: host,
|
||||||
port: config.port,
|
port: config.port,
|
||||||
secure: config.secure,
|
secure: config.secure,
|
||||||
auth: {
|
auth: {
|
||||||
user: user,
|
user: user,
|
||||||
pass: pass,
|
pass: pass,
|
||||||
},
|
},
|
||||||
connectionTimeout: 10000, // 10 second timeout
|
connectionTimeout: 10000, // 10 second timeout
|
||||||
greetingTimeout: 10000,
|
greetingTimeout: 10000,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only add TLS settings if encryption is enabled
|
// Only add TLS settings if encryption is enabled
|
||||||
if (config.tls !== false) {
|
if (config.tls !== false) {
|
||||||
transporterConfig.tls = {
|
transporterConfig.tls = {
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport(transporterConfig);
|
try {
|
||||||
|
const transporter = nodemailer.createTransport(transporterConfig);
|
||||||
|
|
||||||
try {
|
// Verify connection
|
||||||
// Verify connection
|
await transporter.verify();
|
||||||
await transporter.verify();
|
console.log(`✅ ${config.name} - Connection successful!`);
|
||||||
console.log(`✅ ${config.name} - Connection successful!`);
|
|
||||||
|
|
||||||
// Send test email for this successful configuration
|
// Send test email for this successful configuration
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
from: from || user,
|
from: from || user,
|
||||||
to: to,
|
to: to,
|
||||||
subject: `SMTP Auto-Discovery: ${config.name} - SUCCESS`,
|
subject: `SMTP Auto-Discovery: ${config.name} - SUCCESS`,
|
||||||
html: `
|
html: `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -384,42 +383,52 @@ app.post('/api/auto-test-smtp', async (req, res) => {
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const info = await transporter.sendMail(mailOptions);
|
const info = await transporter.sendMail(mailOptions);
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
config: config.name,
|
config: config.name,
|
||||||
port: config.port,
|
port: config.port,
|
||||||
secure: config.secure,
|
secure: config.secure,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
messageId: info.messageId,
|
messageId: info.messageId,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`📧 Email sent for ${config.name}: ${info.messageId}`);
|
console.log(`📧 Email sent for ${config.name}: ${info.messageId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(`❌ ${config.name} - Failed: ${error.message}`);
|
console.log(`❌ ${config.name} - Failed: ${error.message}`);
|
||||||
results.push({
|
results.push({
|
||||||
config: config.name,
|
config: config.name,
|
||||||
port: config.port,
|
port: config.port,
|
||||||
secure: config.secure,
|
secure: config.secure,
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
error: error.message,
|
error: error.message,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return summary of all tests
|
// Return summary of all tests
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: `Auto-discovery complete. Found ${successCount} working configuration(s).`,
|
message: `Auto-discovery complete. Found ${successCount} working configuration(s).`,
|
||||||
totalTests: configurations.length,
|
totalTests: configurations.length,
|
||||||
successfulConfigs: successCount,
|
successfulConfigs: successCount,
|
||||||
results: results,
|
results: results,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Global Error Handler
|
||||||
|
app.use((err, req, res, next) => {
|
||||||
|
console.error("Unhandled Error:", err);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: "Internal Server Error",
|
||||||
|
error: err.message || "Unknown error occurred"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server running at http://localhost:${port}`);
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user