/** * SMTP Server Constants * This file contains all constants and enums used by the SMTP server */ import { SmtpState } from '../interfaces.js'; // Re-export SmtpState enum from the main interfaces file export { SmtpState }; /** * SMTP Response Codes * Based on RFC 5321 and common SMTP practice */ export enum SmtpResponseCode { // Success codes (2xx) SUCCESS = 250, // Requested mail action okay, completed SYSTEM_STATUS = 211, // System status, or system help reply HELP_MESSAGE = 214, // Help message SERVICE_READY = 220, // Service ready SERVICE_CLOSING = 221, // Service closing transmission channel AUTHENTICATION_SUCCESSFUL = 235, // Authentication successful OK = 250, // Requested mail action okay, completed FORWARD = 251, // User not local; will forward to CANNOT_VRFY = 252, // Cannot VRFY user, but will accept message and attempt delivery // Intermediate codes (3xx) MORE_INFO_NEEDED = 334, // Server challenge for authentication START_MAIL_INPUT = 354, // Start mail input; end with . // Temporary error codes (4xx) SERVICE_NOT_AVAILABLE = 421, // Service not available, closing transmission channel MAILBOX_TEMPORARILY_UNAVAILABLE = 450, // Requested mail action not taken: mailbox unavailable LOCAL_ERROR = 451, // Requested action aborted: local error in processing INSUFFICIENT_STORAGE = 452, // Requested action not taken: insufficient system storage TLS_UNAVAILABLE_TEMP = 454, // TLS not available due to temporary reason // Permanent error codes (5xx) SYNTAX_ERROR = 500, // Syntax error, command unrecognized SYNTAX_ERROR_PARAMETERS = 501, // Syntax error in parameters or arguments COMMAND_NOT_IMPLEMENTED = 502, // Command not implemented BAD_SEQUENCE = 503, // Bad sequence of commands COMMAND_PARAMETER_NOT_IMPLEMENTED = 504, // Command parameter not implemented AUTH_REQUIRED = 530, // Authentication required AUTH_FAILED = 535, // Authentication credentials invalid MAILBOX_UNAVAILABLE = 550, // Requested action not taken: mailbox unavailable USER_NOT_LOCAL = 551, // User not local; please try EXCEEDED_STORAGE = 552, // Requested mail action aborted: exceeded storage allocation MAILBOX_NAME_INVALID = 553, // Requested action not taken: mailbox name not allowed TRANSACTION_FAILED = 554, // Transaction failed MAIL_RCPT_PARAMETERS_INVALID = 555, // MAIL FROM/RCPT TO parameters not recognized or not implemented } /** * SMTP Command Types */ export enum SmtpCommand { HELO = 'HELO', EHLO = 'EHLO', MAIL_FROM = 'MAIL', RCPT_TO = 'RCPT', DATA = 'DATA', RSET = 'RSET', NOOP = 'NOOP', QUIT = 'QUIT', STARTTLS = 'STARTTLS', AUTH = 'AUTH', HELP = 'HELP', VRFY = 'VRFY', EXPN = 'EXPN', } /** * Security log event types */ export enum SecurityEventType { CONNECTION = 'connection', AUTHENTICATION = 'authentication', COMMAND = 'command', DATA = 'data', IP_REPUTATION = 'ip_reputation', TLS_NEGOTIATION = 'tls_negotiation', DKIM = 'dkim', SPF = 'spf', DMARC = 'dmarc', EMAIL_VALIDATION = 'email_validation', SPAM = 'spam', ACCESS_CONTROL = 'access_control', } /** * Security log levels */ export enum SecurityLogLevel { DEBUG = 'debug', INFO = 'info', WARN = 'warn', ERROR = 'error', } /** * SMTP Server Defaults */ export const SMTP_DEFAULTS = { // Default timeouts in milliseconds CONNECTION_TIMEOUT: 30000, // 30 seconds SOCKET_TIMEOUT: 300000, // 5 minutes DATA_TIMEOUT: 60000, // 1 minute CLEANUP_INTERVAL: 5000, // 5 seconds // Default limits MAX_CONNECTIONS: 100, MAX_RECIPIENTS: 100, MAX_MESSAGE_SIZE: 10485760, // 10MB // Default ports SMTP_PORT: 25, SUBMISSION_PORT: 587, SECURE_PORT: 465, // Default hostname HOSTNAME: 'mail.lossless.one', // CRLF line ending required by SMTP protocol CRLF: '\r\n', }; /** * SMTP Command Patterns * Regular expressions for parsing SMTP commands */ export const SMTP_PATTERNS = { // Match EHLO/HELO command: "EHLO example.com" // Made very permissive to handle various client implementations EHLO: /^(?:EHLO|HELO)\s+(.+)$/i, // Match MAIL FROM command: "MAIL FROM: [PARAM=VALUE]" // Made more permissive with whitespace and parameter formats MAIL_FROM: /^MAIL\s+FROM\s*:\s*<([^>]*)>((?:\s+[a-zA-Z0-9][a-zA-Z0-9\-]*(?:=[^\s]+)?)*)$/i, // Match RCPT TO command: "RCPT TO: [PARAM=VALUE]" // Made more permissive with whitespace and parameter formats RCPT_TO: /^RCPT\s+TO\s*:\s*<([^>]*)>((?:\s+[a-zA-Z0-9][a-zA-Z0-9\-]*(?:=[^\s]+)?)*)$/i, // Match parameter format: "PARAM=VALUE" PARAM: /\s+([A-Za-z0-9][A-Za-z0-9\-]*)(?:=([^\s]+))?/g, // Match email address format - basic validation // This pattern rejects common invalid formats while being permissive for edge cases // Checks: no spaces, has @, has domain with dot, no double dots, proper domain format EMAIL: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, // Match end of DATA marker: \r\n.\r\n or just .\r\n at the start of a line (to handle various client implementations) END_DATA: /(\r\n\.\r\n$)|(\n\.\r\n$)|(\r\n\.\n$)|(\n\.\n$)|^\.(\r\n|\n)$/, }; /** * SMTP Extension List * These extensions are advertised in the EHLO response */ export const SMTP_EXTENSIONS = { // Basic extensions (RFC 1869) PIPELINING: 'PIPELINING', SIZE: 'SIZE', EIGHTBITMIME: '8BITMIME', // Security extensions STARTTLS: 'STARTTLS', AUTH: 'AUTH', // Additional extensions ENHANCEDSTATUSCODES: 'ENHANCEDSTATUSCODES', HELP: 'HELP', CHUNKING: 'CHUNKING', DSN: 'DSN', // Format an extension with a parameter formatExtension(name: string, parameter?: string | number): string { return parameter !== undefined ? `${name} ${parameter}` : name; } };