import * as plugins from '../../plugins.js'; import { logger } from '../../logger.js'; import { SecurityLogger, SecurityLogLevel, SecurityEventType } from '../../security/index.js'; import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js'; import { MtaConnectionError, MtaAuthenticationError, MtaDeliveryError, MtaConfigurationError, MtaTimeoutError, MtaProtocolError } from '../../errors/index.js'; import { Email } from '../core/classes.email.js'; /** * SMTP client for sending emails to remote mail servers */ export class SmtpClient { options; connected = false; socket; supportedExtensions = new Set(); /** * Create a new SMTP client instance * @param options SMTP client connection options */ constructor(options) { // Set default options this.options = { ...options, connectionTimeout: options.connectionTimeout || 30000, // 30 seconds socketTimeout: options.socketTimeout || 60000, // 60 seconds commandTimeout: options.commandTimeout || 30000, // 30 seconds secure: options.secure || false, domain: options.domain || 'localhost', tls: { rejectUnauthorized: options.tls?.rejectUnauthorized !== false, // Default to true minVersion: options.tls?.minVersion || 'TLSv1.2' } }; } /** * Connect to the SMTP server */ async connect() { if (this.connected && this.socket) { return; } try { logger.log('info', `Connecting to SMTP server ${this.options.host}:${this.options.port}`); // Create socket const socket = new plugins.net.Socket(); // Set timeouts socket.setTimeout(this.options.socketTimeout); // Connect to the server await new Promise((resolve, reject) => { // Handle connection events socket.once('connect', () => { logger.log('debug', `Connected to ${this.options.host}:${this.options.port}`); resolve(); }); socket.once('timeout', () => { reject(MtaConnectionError.timeout(this.options.host, this.options.port, this.options.connectionTimeout)); }); socket.once('error', (err) => { if (err.code === 'ECONNREFUSED') { reject(MtaConnectionError.refused(this.options.host, this.options.port)); } else if (err.code === 'ENOTFOUND') { reject(MtaConnectionError.dnsError(this.options.host, err)); } else { reject(new MtaConnectionError(`Connection error to ${this.options.host}:${this.options.port}: ${err.message}`, { data: { host: this.options.host, port: this.options.port, error: err.message, code: err.code } })); } }); // Connect to the server const connectOptions = { host: this.options.host, port: this.options.port }; // For direct TLS connections if (this.options.secure) { const tlsSocket = plugins.tls.connect({ ...connectOptions, rejectUnauthorized: this.options.tls.rejectUnauthorized, minVersion: this.options.tls.minVersion, ca: this.options.tls.ca ? [this.options.tls.ca] : undefined }); tlsSocket.once('secureConnect', () => { logger.log('debug', `Secure connection established to ${this.options.host}:${this.options.port}`); this.socket = tlsSocket; resolve(); }); tlsSocket.once('error', (err) => { reject(new MtaConnectionError(`TLS connection error to ${this.options.host}:${this.options.port}: ${err.message}`, { data: { host: this.options.host, port: this.options.port, error: err.message, code: err.code } })); }); tlsSocket.setTimeout(this.options.socketTimeout); tlsSocket.once('timeout', () => { reject(MtaConnectionError.timeout(this.options.host, this.options.port, this.options.connectionTimeout)); }); } else { socket.connect(connectOptions); this.socket = socket; } }); // Wait for server greeting const greeting = await this.readResponse(); if (!greeting.startsWith('220')) { throw new MtaConnectionError(`Unexpected greeting from server: ${greeting}`, { data: { host: this.options.host, port: this.options.port, greeting } }); } // Send EHLO await this.sendEhlo(); // Start TLS if not secure and supported if (!this.options.secure && this.supportedExtensions.has('STARTTLS')) { await this.startTls(); // Send EHLO again after STARTTLS await this.sendEhlo(); } // Authenticate if credentials provided if (this.options.auth) { await this.authenticate(); } this.connected = true; logger.log('info', `Successfully connected to SMTP server ${this.options.host}:${this.options.port}`); // Set up error handling for the socket this.socket.on('error', (err) => { logger.log('error', `Socket error: ${err.message}`); this.connected = false; this.socket = undefined; }); this.socket.on('close', () => { logger.log('debug', 'Socket closed'); this.connected = false; this.socket = undefined; }); this.socket.on('timeout', () => { logger.log('error', 'Socket timeout'); this.connected = false; if (this.socket) { this.socket.destroy(); this.socket = undefined; } }); } catch (error) { // Clean up socket if connection failed if (this.socket) { this.socket.destroy(); this.socket = undefined; } logger.log('error', `Failed to connect to SMTP server: ${error.message}`); throw error; } } /** * Send EHLO command to the server */ async sendEhlo() { // Clear previous extensions this.supportedExtensions.clear(); // Send EHLO - don't allow pipelining for this command const response = await this.sendCommand(`EHLO ${this.options.domain}`, false); // Parse supported extensions const lines = response.split('\r\n'); for (let i = 1; i < lines.length; i++) { const line = lines[i]; if (line.startsWith('250-') || line.startsWith('250 ')) { const extension = line.substring(4).split(' ')[0]; this.supportedExtensions.add(extension); } } // Check if server supports pipelining this.supportsPipelining = this.supportedExtensions.has('PIPELINING'); logger.log('debug', `Server supports extensions: ${Array.from(this.supportedExtensions).join(', ')}`); if (this.supportsPipelining) { logger.log('info', 'Server supports PIPELINING - will use for improved performance'); } } /** * Start TLS negotiation */ async startTls() { logger.log('debug', 'Starting TLS negotiation'); // Send STARTTLS command const response = await this.sendCommand('STARTTLS'); if (!response.startsWith('220')) { throw new MtaConnectionError(`Failed to start TLS: ${response}`, { data: { host: this.options.host, port: this.options.port, response } }); } if (!this.socket) { throw new MtaConnectionError('No socket available for TLS upgrade', { data: { host: this.options.host, port: this.options.port } }); } // Upgrade socket to TLS const currentSocket = this.socket; this.socket = await this.upgradeTls(currentSocket); } /** * Upgrade socket to TLS * @param socket Original socket */ async upgradeTls(socket) { return new Promise((resolve, reject) => { const tlsOptions = { socket, servername: this.options.host, rejectUnauthorized: this.options.tls.rejectUnauthorized, minVersion: this.options.tls.minVersion, ca: this.options.tls.ca ? [this.options.tls.ca] : undefined }; const tlsSocket = plugins.tls.connect(tlsOptions); tlsSocket.once('secureConnect', () => { logger.log('debug', 'TLS negotiation successful'); resolve(tlsSocket); }); tlsSocket.once('error', (err) => { reject(new MtaConnectionError(`TLS error: ${err.message}`, { data: { host: this.options.host, port: this.options.port, error: err.message, code: err.code } })); }); tlsSocket.setTimeout(this.options.socketTimeout); tlsSocket.once('timeout', () => { reject(MtaTimeoutError.commandTimeout('STARTTLS', this.options.host, this.options.socketTimeout)); }); }); } /** * Authenticate with the server */ async authenticate() { if (!this.options.auth) { return; } const { user, pass, method = 'LOGIN' } = this.options.auth; logger.log('debug', `Authenticating as ${user} using ${method}`); try { switch (method) { case 'PLAIN': await this.authPlain(user, pass); break; case 'LOGIN': await this.authLogin(user, pass); break; case 'OAUTH2': await this.authOAuth2(user, pass); break; default: throw new MtaAuthenticationError(`Authentication method ${method} not supported by client`, { data: { method } }); } logger.log('info', `Successfully authenticated as ${user}`); } catch (error) { logger.log('error', `Authentication failed: ${error.message}`); throw error; } } /** * Authenticate using PLAIN method * @param user Username * @param pass Password */ async authPlain(user, pass) { // PLAIN authentication format: \0username\0password const authString = Buffer.from(`\0${user}\0${pass}`).toString('base64'); const response = await this.sendCommand(`AUTH PLAIN ${authString}`); if (!response.startsWith('235')) { throw MtaAuthenticationError.invalidCredentials(this.options.host, user); } } /** * Authenticate using LOGIN method * @param user Username * @param pass Password */ async authLogin(user, pass) { // Start LOGIN authentication const response = await this.sendCommand('AUTH LOGIN'); if (!response.startsWith('334')) { throw new MtaAuthenticationError(`Server did not accept AUTH LOGIN: ${response}`, { data: { host: this.options.host, response } }); } // Send username (base64) const userResponse = await this.sendCommand(Buffer.from(user).toString('base64')); if (!userResponse.startsWith('334')) { throw MtaAuthenticationError.invalidCredentials(this.options.host, user); } // Send password (base64) const passResponse = await this.sendCommand(Buffer.from(pass).toString('base64')); if (!passResponse.startsWith('235')) { throw MtaAuthenticationError.invalidCredentials(this.options.host, user); } } /** * Authenticate using OAuth2 method * @param user Username * @param token OAuth2 token */ async authOAuth2(user, token) { // XOAUTH2 format const authString = `user=${user}\x01auth=Bearer ${token}\x01\x01`; const response = await this.sendCommand(`AUTH XOAUTH2 ${Buffer.from(authString).toString('base64')}`); if (!response.startsWith('235')) { throw MtaAuthenticationError.invalidCredentials(this.options.host, user); } } /** * Send an email through the SMTP client * @param email Email to send * @param processingMode Optional processing mode */ async sendMail(email, processingMode) { // Ensure we're connected if (!this.connected || !this.socket) { await this.connect(); } const startTime = Date.now(); const result = { success: false, acceptedRecipients: [], rejectedRecipients: [], timestamp: startTime, secure: this.options.secure || this.socket instanceof plugins.tls.TLSSocket, authenticated: !!this.options.auth }; try { logger.log('info', `Sending email to ${email.getAllRecipients().join(', ')}`); // Apply DKIM signing if configured if (this.options.dkim?.enabled) { await this.applyDkimSignature(email); result.dkimSigned = true; } // Get envelope and recipients const envelope_from = email.getEnvelopeFrom() || email.from; const recipients = email.getAllRecipients(); // Check if we can use pipelining for MAIL FROM and RCPT TO commands if (this.supportsPipelining && recipients.length > 0) { logger.log('debug', 'Using SMTP pipelining for sending'); // Send MAIL FROM command first (always needed) const mailFromCmd = `MAIL FROM:<${envelope_from}> SIZE=${this.getEmailSize(email)}`; let mailFromResponse; try { mailFromResponse = await this.sendCommand(mailFromCmd); if (!mailFromResponse.startsWith('250')) { throw new MtaDeliveryError(`MAIL FROM command failed: ${mailFromResponse}`, { data: { command: mailFromCmd, response: mailFromResponse } }); } } catch (error) { logger.log('error', `MAIL FROM failed: ${error.message}`); throw error; } // Pipeline all RCPT TO commands const rcptPromises = recipients.map(recipient => { return this.sendCommand(`RCPT TO:<${recipient}>`) .then(response => { if (response.startsWith('250')) { result.acceptedRecipients.push(recipient); return { recipient, accepted: true, response }; } else { result.rejectedRecipients.push(recipient); logger.log('warn', `Recipient ${recipient} rejected: ${response}`); return { recipient, accepted: false, response }; } }) .catch(error => { result.rejectedRecipients.push(recipient); logger.log('warn', `Recipient ${recipient} rejected with error: ${error.message}`); return { recipient, accepted: false, error: error.message }; }); }); // Wait for all RCPT TO commands to complete await Promise.all(rcptPromises); } else { // Fall back to sequential commands if pipelining not supported logger.log('debug', 'Using sequential SMTP commands for sending'); // Send MAIL FROM await this.sendCommand(`MAIL FROM:<${envelope_from}> SIZE=${this.getEmailSize(email)}`); // Send RCPT TO for each recipient for (const recipient of recipients) { try { await this.sendCommand(`RCPT TO:<${recipient}>`); result.acceptedRecipients.push(recipient); } catch (error) { logger.log('warn', `Recipient ${recipient} rejected: ${error.message}`); result.rejectedRecipients.push(recipient); } } } // Check if at least one recipient was accepted if (result.acceptedRecipients.length === 0) { throw new MtaDeliveryError('All recipients were rejected', { data: { recipients, rejectedRecipients: result.rejectedRecipients } }); } // Send DATA const dataResponse = await this.sendCommand('DATA'); if (!dataResponse.startsWith('354')) { throw new MtaProtocolError(`Failed to start DATA phase: ${dataResponse}`, { data: { response: dataResponse } }); } // Format email content efficiently const emailContent = await this.getFormattedEmail(email); // Send email content const finalResponse = await this.sendCommand(emailContent + '\r\n.'); // Extract message ID if available const messageIdMatch = finalResponse.match(/\[(.*?)\]/); if (messageIdMatch) { result.messageId = messageIdMatch[1]; } result.success = true; result.response = finalResponse; logger.log('info', `Email sent successfully to ${result.acceptedRecipients.join(', ')}`); // Log security event SecurityLogger.getInstance().logEvent({ level: SecurityLogLevel.INFO, type: SecurityEventType.EMAIL_DELIVERY, message: 'Email sent successfully', details: { recipients: result.acceptedRecipients, rejectedRecipients: result.rejectedRecipients, messageId: result.messageId, secure: result.secure, authenticated: result.authenticated, server: `${this.options.host}:${this.options.port}`, dkimSigned: result.dkimSigned }, success: true }); return result; } catch (error) { logger.log('error', `Failed to send email: ${error.message}`); // Format error for result result.error = error.message; // Extract SMTP code if available if (error.context?.data?.statusCode) { result.responseCode = error.context.data.statusCode; } // Log security event SecurityLogger.getInstance().logEvent({ level: SecurityLogLevel.ERROR, type: SecurityEventType.EMAIL_DELIVERY, message: 'Email delivery failed', details: { error: error.message, server: `${this.options.host}:${this.options.port}`, recipients: email.getAllRecipients(), acceptedRecipients: result.acceptedRecipients, rejectedRecipients: result.rejectedRecipients, secure: result.secure, authenticated: result.authenticated }, success: false }); return result; } } /** * Apply DKIM signature to email * @param email Email to sign */ async applyDkimSignature(email) { if (!this.options.dkim?.enabled || !this.options.dkim?.privateKey) { return; } try { logger.log('debug', `Signing email with DKIM for domain ${this.options.dkim.domain}`); const emailContent = await this.getFormattedEmail(email); // Sign via Rust bridge const bridge = RustSecurityBridge.getInstance(); const signResult = await bridge.signDkim({ rawMessage: emailContent, domain: this.options.dkim.domain, selector: this.options.dkim.selector, privateKey: this.options.dkim.privateKey, }); if (signResult.header) { email.addHeader('DKIM-Signature', signResult.header); } logger.log('debug', 'DKIM signature applied successfully'); } catch (error) { logger.log('error', `Failed to apply DKIM signature: ${error.message}`); throw error; } } /** * Format email for SMTP transmission * @param email Email to format */ async getFormattedEmail(email) { // This is a simplified implementation // In a full implementation, this would use proper MIME formatting let content = ''; // Add headers content += `From: ${email.from}\r\n`; content += `To: ${email.to.join(', ')}\r\n`; content += `Subject: ${email.subject}\r\n`; content += `Date: ${new Date().toUTCString()}\r\n`; content += `Message-ID: <${plugins.uuid.v4()}@${this.options.domain}>\r\n`; // Add additional headers for (const [name, value] of Object.entries(email.headers || {})) { content += `${name}: ${value}\r\n`; } // Add content type for multipart if (email.attachments && email.attachments.length > 0) { const boundary = `----_=_NextPart_${Math.random().toString(36).substr(2)}`; content += `MIME-Version: 1.0\r\n`; content += `Content-Type: multipart/mixed; boundary="${boundary}"\r\n`; content += `\r\n`; // Add text part content += `--${boundary}\r\n`; content += `Content-Type: text/plain; charset="UTF-8"\r\n`; content += `\r\n`; content += `${email.text}\r\n`; // Add HTML part if present if (email.html) { content += `--${boundary}\r\n`; content += `Content-Type: text/html; charset="UTF-8"\r\n`; content += `\r\n`; content += `${email.html}\r\n`; } // Add attachments for (const attachment of email.attachments) { content += `--${boundary}\r\n`; content += `Content-Type: ${attachment.contentType || 'application/octet-stream'}; name="${attachment.filename}"\r\n`; content += `Content-Disposition: attachment; filename="${attachment.filename}"\r\n`; content += `Content-Transfer-Encoding: base64\r\n`; content += `\r\n`; // Add base64 encoded content const base64Content = attachment.content.toString('base64'); // Split into lines of 76 characters for (let i = 0; i < base64Content.length; i += 76) { content += base64Content.substring(i, i + 76) + '\r\n'; } } // End boundary content += `--${boundary}--\r\n`; } else { // Simple email with just text content += `Content-Type: text/plain; charset="UTF-8"\r\n`; content += `\r\n`; content += `${email.text}\r\n`; } return content; } /** * Get size of email in bytes * @param email Email to measure */ getEmailSize(email) { // Simplified size estimation let size = 0; // Headers size += `From: ${email.from}\r\n`.length; size += `To: ${email.to.join(', ')}\r\n`.length; size += `Subject: ${email.subject}\r\n`.length; // Body size += (email.text?.length || 0) + 2; // +2 for CRLF // HTML part if present if (email.html) { size += email.html.length + 2; } // Attachments for (const attachment of email.attachments || []) { size += attachment.content.length; } // Add overhead for MIME boundaries and headers const overhead = email.attachments?.length ? 1000 + (email.attachments.length * 200) : 200; return size + overhead; } /** * Send SMTP command and wait for response * @param command SMTP command to send */ // Queue for command pipelining commandQueue = []; // Flag to indicate if we're currently processing commands processingCommands = false; // Flag to indicate if server supports pipelining supportsPipelining = false; /** * Send an SMTP command and wait for response * @param command SMTP command to send * @param allowPipelining Whether this command can be pipelined */ async sendCommand(command, allowPipelining = true) { if (!this.socket) { throw new MtaConnectionError('Not connected to server', { data: { host: this.options.host, port: this.options.port } }); } // Log command if not sensitive if (!command.startsWith('AUTH')) { logger.log('debug', `> ${command}`); } else { logger.log('debug', '> AUTH ***'); } return new Promise((resolve, reject) => { // Set up timeout for command const timeout = setTimeout(() => { // Remove this command from the queue if it times out const index = this.commandQueue.findIndex(item => item.command === command); if (index !== -1) { this.commandQueue.splice(index, 1); } reject(MtaTimeoutError.commandTimeout(command.split(' ')[0], this.options.host, this.options.commandTimeout)); }, this.options.commandTimeout); // Add command to the queue this.commandQueue.push({ command, resolve, reject, timeout }); // Process command queue if we can pipeline or if not currently processing commands if ((this.supportsPipelining && allowPipelining) || !this.processingCommands) { this.processCommandQueue(); } }); } /** * Process the command queue - either one by one or pipelined if supported */ processCommandQueue() { if (this.processingCommands || this.commandQueue.length === 0 || !this.socket) { return; } this.processingCommands = true; try { // If pipelining is supported, send all commands at once if (this.supportsPipelining) { // Send all commands in queue at once const commands = this.commandQueue.map(item => item.command).join('\r\n') + '\r\n'; this.socket.write(commands, (err) => { if (err) { // Handle write error for all commands const error = new MtaConnectionError(`Failed to send commands: ${err.message}`, { data: { error: err.message } }); // Fail all pending commands while (this.commandQueue.length > 0) { const item = this.commandQueue.shift(); clearTimeout(item.timeout); item.reject(error); } this.processingCommands = false; } }); // Process responses one by one in order this.processResponses(); } else { // Process commands one by one if pipelining not supported this.processNextCommand(); } } catch (error) { logger.log('error', `Error processing command queue: ${error.message}`); this.processingCommands = false; } } /** * Process the next command in the queue (non-pipelined mode) */ processNextCommand() { if (this.commandQueue.length === 0 || !this.socket) { this.processingCommands = false; return; } const currentCommand = this.commandQueue[0]; this.socket.write(currentCommand.command + '\r\n', (err) => { if (err) { // Handle write error const error = new MtaConnectionError(`Failed to send command: ${err.message}`, { data: { command: currentCommand.command.split(' ')[0], error: err.message } }); // Remove from queue this.commandQueue.shift(); clearTimeout(currentCommand.timeout); currentCommand.reject(error); // Continue with next command this.processNextCommand(); return; } // Read response this.readResponse() .then((response) => { // Remove from queue and resolve this.commandQueue.shift(); clearTimeout(currentCommand.timeout); currentCommand.resolve(response); // Process next command this.processNextCommand(); }) .catch((err) => { // Remove from queue and reject this.commandQueue.shift(); clearTimeout(currentCommand.timeout); currentCommand.reject(err); // Process next command this.processNextCommand(); }); }); } /** * Process responses for pipelined commands */ async processResponses() { try { // Process responses for each command in order while (this.commandQueue.length > 0) { const currentCommand = this.commandQueue[0]; try { // Wait for response const response = await this.readResponse(); // Remove from queue and resolve this.commandQueue.shift(); clearTimeout(currentCommand.timeout); currentCommand.resolve(response); } catch (error) { // Remove from queue and reject this.commandQueue.shift(); clearTimeout(currentCommand.timeout); currentCommand.reject(error); // Stop processing if this is a critical error if (error instanceof MtaConnectionError && (error.message.includes('Connection closed') || error.message.includes('Not connected'))) { break; } } } } catch (error) { logger.log('error', `Error processing responses: ${error.message}`); } finally { this.processingCommands = false; } } /** * Read response from the server */ async readResponse() { if (!this.socket) { throw new MtaConnectionError('Not connected to server', { data: { host: this.options.host, port: this.options.port } }); } return new Promise((resolve, reject) => { // Use an array to collect response chunks instead of string concatenation const responseChunks = []; // Single function to clean up all listeners const cleanupListeners = () => { if (!this.socket) return; this.socket.removeListener('data', onData); this.socket.removeListener('error', onError); this.socket.removeListener('close', onClose); this.socket.removeListener('end', onEnd); }; const onData = (data) => { // Store buffer directly, avoiding unnecessary string conversion responseChunks.push(data); // Convert to string only for response checking const responseData = Buffer.concat(responseChunks).toString(); // Check if this is a complete response if (this.isCompleteResponse(responseData)) { // Clean up listeners cleanupListeners(); const trimmedResponse = responseData.trim(); logger.log('debug', `< ${trimmedResponse}`); // Check if this is an error response if (this.isErrorResponse(responseData)) { const code = responseData.substring(0, 3); reject(this.createErrorFromResponse(trimmedResponse, code)); } else { resolve(trimmedResponse); } } }; const onError = (err) => { cleanupListeners(); reject(new MtaConnectionError(`Socket error while waiting for response: ${err.message}`, { data: { error: err.message } })); }; const onClose = () => { cleanupListeners(); const responseData = Buffer.concat(responseChunks).toString(); reject(new MtaConnectionError('Connection closed while waiting for response', { data: { partialResponse: responseData } })); }; const onEnd = () => { cleanupListeners(); const responseData = Buffer.concat(responseChunks).toString(); reject(new MtaConnectionError('Connection ended while waiting for response', { data: { partialResponse: responseData } })); }; // Set up listeners this.socket.on('data', onData); this.socket.once('error', onError); this.socket.once('close', onClose); this.socket.once('end', onEnd); }); } /** * Check if the response is complete * @param response Response to check */ isCompleteResponse(response) { // Check if it's a multi-line response const lines = response.split('\r\n'); const lastLine = lines[lines.length - 2]; // Second to last because of the trailing CRLF // Check if the last line starts with a code followed by a space // If it does, this is a complete response if (lastLine && /^\d{3} /.test(lastLine)) { return true; } // For single line responses if (lines.length === 2 && lines[0].length >= 3 && /^\d{3} /.test(lines[0])) { return true; } return false; } /** * Check if the response is an error * @param response Response to check */ isErrorResponse(response) { // Get the status code (first 3 characters) const code = response.substring(0, 3); // 4xx and 5xx are error codes return code.startsWith('4') || code.startsWith('5'); } /** * Create appropriate error from response * @param response Error response * @param code SMTP status code */ createErrorFromResponse(response, code) { // Extract message part const message = response.substring(4).trim(); switch (code.charAt(0)) { case '4': // Temporary errors return MtaDeliveryError.temporary(message, 'recipient', code, response); case '5': // Permanent errors return MtaDeliveryError.permanent(message, 'recipient', code, response); default: return new MtaDeliveryError(`Unexpected error response: ${response}`, { data: { response, code } }); } } /** * Close the connection to the server */ async close() { if (!this.connected || !this.socket) { return; } try { // Send QUIT await this.sendCommand('QUIT'); } catch (error) { logger.log('warn', `Error sending QUIT command: ${error.message}`); } finally { // Close socket this.socket.destroy(); this.socket = undefined; this.connected = false; logger.log('info', 'SMTP connection closed'); } } /** * Checks if the connection is active */ isConnected() { return this.connected && !!this.socket; } /** * Update SMTP client options * @param options New options */ updateOptions(options) { this.options = { ...this.options, ...options }; logger.log('info', 'SMTP client options updated'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zbXRwLmNsaWVudC5sZWdhY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9tYWlsL2RlbGl2ZXJ5L2NsYXNzZXMuc210cC5jbGllbnQubGVnYWN5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLGlCQUFpQixFQUNsQixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBRWxGLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsc0JBQXNCLEVBQ3RCLGdCQUFnQixFQUNoQixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLGdCQUFnQixFQUNqQixNQUFNLHVCQUF1QixDQUFDO0FBRS9CLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQWtMakQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUNiLE9BQU8sQ0FBcUI7SUFDNUIsU0FBUyxHQUFZLEtBQUssQ0FBQztJQUMzQixNQUFNLENBQThDO0lBQ3BELG1CQUFtQixHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRXJEOzs7T0FHRztJQUNILFlBQVksT0FBMkI7UUFDckMsc0JBQXNCO1FBQ3RCLElBQUksQ0FBQyxPQUFPLEdBQUc7WUFDYixHQUFHLE9BQU87WUFDVixpQkFBaUIsRUFBRSxPQUFPLENBQUMsaUJBQWlCLElBQUksS0FBSyxFQUFFLGFBQWE7WUFDcEUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhLElBQUksS0FBSyxFQUFFLGFBQWE7WUFDNUQsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjLElBQUksS0FBSyxFQUFFLGFBQWE7WUFDOUQsTUFBTSxFQUFFLE9BQU8sQ0FB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