110 lines
4.2 KiB
JavaScript
110 lines
4.2 KiB
JavaScript
import { connect } from 'tls'; // For SSL and STARTTLS
|
|
import { Socket } from 'net'; // For non-encrypted connections (before STARTTLS)
|
|
|
|
class SMTPClient {
|
|
constructor(host, port = 587, auth) {
|
|
this.host = host;
|
|
this.port = port;
|
|
this.auth = auth;
|
|
this.socket = null;
|
|
}
|
|
|
|
connect() {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.port === 465) {
|
|
// SSL connection (SMTPS)
|
|
this.socket = connect({ host: this.host, port: this.port, rejectUnauthorized: false }, () => {
|
|
console.log(`Connected to SMTP server with SSL at ${this.host}:${this.port}`);
|
|
resolve();
|
|
});
|
|
} else if (this.port === 587) {
|
|
// Non-encrypted connection, STARTTLS will be applied later
|
|
this.socket = new Socket();
|
|
this.socket.connect(this.port, this.host, () => {
|
|
console.log(`Connected to SMTP server at ${this.host}:${this.port}`);
|
|
resolve();
|
|
});
|
|
} else {
|
|
// Plain non-encrypted connection (used for ports like 2525)
|
|
this.socket = new Socket();
|
|
this.socket.connect(this.port, this.host, () => {
|
|
console.log(`Connected to SMTP server at ${this.host}:${this.port} (No SSL/TLS)`);
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
this.socket.on('error', (err) => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
|
|
async sendEmail(from, to, subject, body) {
|
|
try {
|
|
if (this.port === 587) {
|
|
// If using STARTTLS
|
|
await this.sendCommand(`EHLO ${this.host}`);
|
|
await this.sendCommand(`STARTTLS`);
|
|
this.upgradeToTLS(); // Upgrade connection to TLS after STARTTLS
|
|
}
|
|
|
|
await this.sendCommand(`EHLO ${this.host}`); // Send EHLO again after STARTTLS or for SSL
|
|
await this.sendCommand(`AUTH LOGIN`);
|
|
await this.sendAuth();
|
|
await this.sendCommand(`MAIL FROM:<${from}>`);
|
|
await this.sendCommand(`RCPT TO:<${to}>`);
|
|
await this.sendCommand('DATA');
|
|
await this.sendCommand(`${body}\r\n.`);
|
|
await this.sendCommand('QUIT');
|
|
} catch (error) {
|
|
throw new Error(`Error sending email: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async sendAuth() {
|
|
const base64User = Buffer.from(this.auth.user).toString('base64');
|
|
const base64Pass = Buffer.from(this.auth.pass).toString('base64');
|
|
await this.sendCommand(base64User);
|
|
return await this.sendCommand(base64Pass);
|
|
}
|
|
|
|
sendCommand(command) {
|
|
return new Promise((resolve, reject) => {
|
|
this.socket.write(`${command}\r\n`, (err) => {
|
|
if (err) return reject(err);
|
|
|
|
this.socket.once('data', (data) => {
|
|
const response = data.toString();
|
|
console.log('SMTP Response:', response);
|
|
|
|
if (response.startsWith('250') || response.startsWith('354') || response.startsWith('235')) {
|
|
resolve(response);
|
|
} else if (response.startsWith('334')) {
|
|
resolve(); // Continue authentication
|
|
} else if (response.startsWith('221')) {
|
|
console.log('SMTP session closed successfully.');
|
|
resolve(response);
|
|
} else if (response.startsWith('220')) {
|
|
resolve(); // Initial greeting
|
|
} else {
|
|
console.error('SMTP Error:', response);
|
|
reject(new Error(`SMTP Error: ${response}`));
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
// Upgrade the current connection to TLS (STARTTLS mode)
|
|
upgradeToTLS() {
|
|
this.socket = connect({
|
|
socket: this.socket, // Upgrade the existing socket to TLS
|
|
rejectUnauthorized: false
|
|
}, () => {
|
|
console.log(`Connection upgraded to TLS`);
|
|
});
|
|
}
|
|
}
|
|
|
|
export default SMTPClient;
|