2025-05-23 00:06:07 +00:00

655 lines
12 KiB
TypeScript

/**
* SMTP Server Interfaces
* Defines all the interfaces used by the SMTP server implementation
*/
import * as plugins from '../../../plugins.js';
import type { Email } from '../../core/classes.email.js';
import type { UnifiedEmailServer } from '../../routing/classes.unified.email.server.js';
// Re-export types from other modules
import { SmtpState } from '../interfaces.js';
import { SmtpCommand } from './constants.js';
export { SmtpState, SmtpCommand };
export type { IEnvelopeRecipient } from '../interfaces.js';
/**
* Interface for components that need cleanup
*/
export interface IDestroyable {
/**
* Clean up all resources (timers, listeners, etc)
*/
destroy(): void | Promise<void>;
}
/**
* SMTP authentication credentials
*/
export interface ISmtpAuth {
/**
* Username for authentication
*/
username: string;
/**
* Password for authentication
*/
password: string;
}
/**
* SMTP envelope (sender and recipients)
*/
export interface ISmtpEnvelope {
/**
* Mail from address
*/
mailFrom: {
address: string;
args?: Record<string, string>;
};
/**
* Recipients list
*/
rcptTo: Array<{
address: string;
args?: Record<string, string>;
}>;
}
/**
* SMTP session representing a client connection
*/
export interface ISmtpSession {
/**
* Unique session identifier
*/
id: string;
/**
* Current state of the SMTP session
*/
state: SmtpState;
/**
* Client's hostname from EHLO/HELO
*/
clientHostname: string | null;
/**
* Whether TLS is active for this session
*/
secure: boolean;
/**
* Authentication status
*/
authenticated: boolean;
/**
* Authentication username if authenticated
*/
username?: string;
/**
* Transaction envelope
*/
envelope: ISmtpEnvelope;
/**
* When the session was created
*/
createdAt: Date;
/**
* Last activity timestamp
*/
lastActivity: number;
/**
* Client's IP address
*/
remoteAddress: string;
/**
* Client's port
*/
remotePort: number;
/**
* Additional session data
*/
data?: Record<string, any>;
/**
* Message size if SIZE extension is used
*/
messageSize?: number;
/**
* Server capabilities advertised to client
*/
capabilities?: string[];
/**
* Buffer for incomplete data
*/
dataBuffer?: string;
/**
* Flag to track if we're currently receiving DATA
*/
receivingData?: boolean;
/**
* The raw email data being received
*/
rawData?: string;
/**
* Greeting sent to client
*/
greeting?: string;
/**
* Whether EHLO has been sent
*/
ehloSent?: boolean;
/**
* Whether HELO has been sent
*/
heloSent?: boolean;
/**
* TLS options for this session
*/
tlsOptions?: any;
/**
* Whether TLS is being used
*/
useTLS?: boolean;
/**
* Mail from address for this transaction
*/
mailFrom?: string;
/**
* Recipients for this transaction
*/
rcptTo?: string[];
/**
* Email data being received
*/
emailData?: string;
/**
* Chunks of email data
*/
emailDataChunks?: string[];
/**
* Timeout ID for data reception
*/
dataTimeoutId?: NodeJS.Timeout;
/**
* Whether connection has ended
*/
connectionEnded?: boolean;
/**
* Size of email data being received
*/
emailDataSize?: number;
/**
* Processing mode for this session
*/
processingMode?: string;
}
/**
* Session manager interface
*/
export interface ISessionManager extends IDestroyable {
/**
* Create a new session for a socket
*/
createSession(socket: plugins.net.Socket | plugins.tls.TLSSocket, secure?: boolean): ISmtpSession;
/**
* Get session by socket
*/
getSession(socket: plugins.net.Socket | plugins.tls.TLSSocket): ISmtpSession | undefined;
/**
* Update session state
*/
updateSessionState(session: ISmtpSession, newState: SmtpState): void;
/**
* Remove a session
*/
removeSession(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
/**
* Clear all sessions
*/
clearAllSessions(): void;
/**
* Get all active sessions
*/
getAllSessions(): ISmtpSession[];
/**
* Get session count
*/
getSessionCount(): number;
/**
* Update last activity for a session
*/
updateLastActivity(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
/**
* Check for timed out sessions
*/
checkTimeouts(timeoutMs: number): ISmtpSession[];
/**
* Update session activity timestamp
*/
updateSessionActivity(session: ISmtpSession): void;
/**
* Replace socket in session (for TLS upgrade)
*/
replaceSocket(oldSocket: plugins.net.Socket | plugins.tls.TLSSocket, newSocket: plugins.net.Socket | plugins.tls.TLSSocket): boolean;
}
/**
* Connection manager interface
*/
export interface IConnectionManager extends IDestroyable {
/**
* Handle a new connection
*/
handleConnection(socket: plugins.net.Socket | plugins.tls.TLSSocket, secure: boolean): Promise<void>;
/**
* Close all active connections
*/
closeAllConnections(): void;
/**
* Get active connection count
*/
getConnectionCount(): number;
/**
* Check if accepting new connections
*/
canAcceptConnection(): boolean;
/**
* Handle new connection (legacy method name)
*/
handleNewConnection(socket: plugins.net.Socket): Promise<void>;
/**
* Handle new secure connection (legacy method name)
*/
handleNewSecureConnection(socket: plugins.tls.TLSSocket): Promise<void>;
/**
* Setup socket event handlers
*/
setupSocketEventHandlers(socket: plugins.net.Socket | plugins.tls.TLSSocket): void;
}
/**
* Command handler interface
*/
export interface ICommandHandler extends IDestroyable {
/**
* Handle an SMTP command
*/
handleCommand(
socket: plugins.net.Socket | plugins.tls.TLSSocket,
command: SmtpCommand,
args: string,
session: ISmtpSession
): Promise<void>;
/**
* Get supported commands for current session state
*/
getSupportedCommands(session: ISmtpSession): SmtpCommand[];
/**
* Process command (legacy method name)
*/
processCommand(socket: plugins.net.Socket | plugins.tls.TLSSocket, command: string): Promise<void>;
}
/**
* Data handler interface
*/
export interface IDataHandler extends IDestroyable {
/**
* Handle email data
*/
handleData(
socket: plugins.net.Socket | plugins.tls.TLSSocket,
data: string,
session: ISmtpSession
): Promise<void>;
/**
* Process a complete email
*/
processEmail(
rawData: string,
session: ISmtpSession
): Promise<Email>;
/**
* Handle data received (legacy method name)
*/
handleDataReceived(socket: plugins.net.Socket | plugins.tls.TLSSocket, data: string): Promise<void>;
/**
* Process email data (legacy method name)
*/
processEmailData(socket: plugins.net.Socket | plugins.tls.TLSSocket, data: string): Promise<void>;
}
/**
* TLS handler interface
*/
export interface ITlsHandler extends IDestroyable {
/**
* Handle STARTTLS command
*/
handleStartTls(
socket: plugins.net.Socket,
session: ISmtpSession
): Promise<plugins.tls.TLSSocket | null>;
/**
* Check if TLS is available
*/
isTlsAvailable(): boolean;
/**
* Get TLS options
*/
getTlsOptions(): plugins.tls.TlsOptions;
/**
* Check if TLS is enabled
*/
isTlsEnabled(): boolean;
}
/**
* Security handler interface
*/
export interface ISecurityHandler extends IDestroyable {
/**
* Check IP reputation
*/
checkIpReputation(socket: plugins.net.Socket | plugins.tls.TLSSocket): Promise<boolean>;
/**
* Validate email address
*/
isValidEmail(email: string): boolean;
/**
* Authenticate user
*/
authenticate(auth: ISmtpAuth): Promise<boolean>;
}
/**
* SMTP server options
*/
export interface ISmtpServerOptions {
/**
* Port to listen on
*/
port: number;
/**
* Hostname of the server
*/
hostname: string;
/**
* Host to bind to (optional, defaults to 0.0.0.0)
*/
host?: string;
/**
* Secure port for TLS connections
*/
securePort?: number;
/**
* TLS/SSL private key (PEM format)
*/
key?: string;
/**
* TLS/SSL certificate (PEM format)
*/
cert?: string;
/**
* CA certificates for TLS (PEM format)
*/
ca?: string;
/**
* Maximum size of messages in bytes
*/
maxSize?: number;
/**
* Maximum number of concurrent connections
*/
maxConnections?: number;
/**
* Authentication options
*/
auth?: {
/**
* Whether authentication is required
*/
required: boolean;
/**
* Allowed authentication methods
*/
methods: ('PLAIN' | 'LOGIN' | 'OAUTH2')[];
};
/**
* Socket timeout in milliseconds (default: 5 minutes / 300000ms)
*/
socketTimeout?: number;
/**
* Initial connection timeout in milliseconds (default: 30 seconds / 30000ms)
*/
connectionTimeout?: number;
/**
* Interval for checking idle sessions in milliseconds (default: 5 seconds / 5000ms)
* For testing, can be set lower (e.g. 1000ms) to detect timeouts more quickly
*/
cleanupInterval?: number;
/**
* Maximum number of recipients allowed per message (default: 100)
*/
maxRecipients?: number;
/**
* Maximum message size in bytes (default: 10MB / 10485760 bytes)
* This is advertised in the EHLO SIZE extension
*/
size?: number;
/**
* Timeout for the DATA command in milliseconds (default: 60000ms / 1 minute)
* This controls how long to wait for the complete email data
*/
dataTimeout?: number;
}
/**
* Result of SMTP transaction
*/
export interface ISmtpTransactionResult {
/**
* Whether the transaction was successful
*/
success: boolean;
/**
* Error message if failed
*/
error?: string;
/**
* Message ID if successful
*/
messageId?: string;
/**
* Resulting email if successful
*/
email?: Email;
}
/**
* Interface for SMTP session events
* These events are emitted by the session manager
*/
export interface ISessionEvents {
created: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
stateChanged: (session: ISmtpSession, previousState: SmtpState, newState: SmtpState) => void;
timeout: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
completed: (session: ISmtpSession, socket: plugins.net.Socket | plugins.tls.TLSSocket) => void;
error: (session: ISmtpSession, error: Error) => void;
}
/**
* SMTP Server interface
*/
export interface ISmtpServer extends IDestroyable {
/**
* Start the SMTP server
*/
listen(): Promise<void>;
/**
* Stop the SMTP server
*/
close(): Promise<void>;
/**
* Get the session manager
*/
getSessionManager(): ISessionManager;
/**
* Get the connection manager
*/
getConnectionManager(): IConnectionManager;
/**
* Get the command handler
*/
getCommandHandler(): ICommandHandler;
/**
* Get the data handler
*/
getDataHandler(): IDataHandler;
/**
* Get the TLS handler
*/
getTlsHandler(): ITlsHandler;
/**
* Get the security handler
*/
getSecurityHandler(): ISecurityHandler;
/**
* Get the server options
*/
getOptions(): ISmtpServerOptions;
/**
* Get the email server reference
*/
getEmailServer(): UnifiedEmailServer;
}
/**
* Configuration for creating SMTP server
*/
export interface ISmtpServerConfig {
/**
* Email server instance
*/
emailServer: UnifiedEmailServer;
/**
* Server options
*/
options: ISmtpServerOptions;
/**
* Optional custom session manager
*/
sessionManager?: ISessionManager;
/**
* Optional custom connection manager
*/
connectionManager?: IConnectionManager;
/**
* Optional custom command handler
*/
commandHandler?: ICommandHandler;
/**
* Optional custom data handler
*/
dataHandler?: IDataHandler;
/**
* Optional custom TLS handler
*/
tlsHandler?: ITlsHandler;
/**
* Optional custom security handler
*/
securityHandler?: ISecurityHandler;
}