update
This commit is contained in:
@@ -189,46 +189,79 @@ export class DataHandler implements IDataHandler {
|
||||
|
||||
/**
|
||||
* Process a complete email
|
||||
* @param rawData - Raw email data
|
||||
* @param session - SMTP session
|
||||
* @returns Promise that resolves with the Email object
|
||||
*/
|
||||
public async processEmail(rawData: string, session: ISmtpSession): Promise<Email> {
|
||||
// Clean up the raw email data
|
||||
let cleanedData = rawData;
|
||||
|
||||
// Remove trailing end-of-data marker: various formats
|
||||
cleanedData = cleanedData
|
||||
.replace(/\r\n\.\r\n$/, '')
|
||||
.replace(/\n\.\r\n$/, '')
|
||||
.replace(/\r\n\.\n$/, '')
|
||||
.replace(/\n\.\n$/, '')
|
||||
.replace(/^\.$/, ''); // Handle ONLY a lone dot as the entire content (not trailing dots)
|
||||
|
||||
// Remove dot-stuffing (RFC 5321, section 4.5.2)
|
||||
cleanedData = cleanedData.replace(/\r\n\.\./g, '\r\n.');
|
||||
|
||||
try {
|
||||
// Parse email into Email object using cleaned data
|
||||
const email = await this.parseEmailFromData(cleanedData, session);
|
||||
|
||||
// Return the parsed email
|
||||
return email;
|
||||
} catch (error) {
|
||||
SmtpLogger.error(`Failed to parse email: ${error instanceof Error ? error.message : String(error)}`, {
|
||||
sessionId: session.id,
|
||||
error: error instanceof Error ? error : new Error(String(error))
|
||||
});
|
||||
|
||||
// Create a minimal email object on error
|
||||
const fallbackEmail = new Email();
|
||||
fallbackEmail.setFromRawData(cleanedData);
|
||||
return fallbackEmail;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse email from raw data
|
||||
* @param rawData - Raw email data
|
||||
* @param session - SMTP session
|
||||
* @returns Email object
|
||||
*/
|
||||
private async parseEmailFromData(rawData: string, session: ISmtpSession): Promise<Email> {
|
||||
const email = new Email();
|
||||
|
||||
// Set raw data
|
||||
email.setFromRawData(rawData);
|
||||
|
||||
// Set envelope information from session
|
||||
if (session.mailFrom) {
|
||||
email.setFrom(session.mailFrom);
|
||||
}
|
||||
|
||||
if (session.rcptTo && session.rcptTo.length > 0) {
|
||||
for (const recipient of session.rcptTo) {
|
||||
email.addTo(recipient);
|
||||
}
|
||||
}
|
||||
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a complete email (legacy method)
|
||||
* @param session - SMTP session
|
||||
* @returns Promise that resolves with the result of the transaction
|
||||
*/
|
||||
public async processEmail(session: ISmtpSession): Promise<ISmtpTransactionResult> {
|
||||
const isLargeMessage = (session.emailDataSize || 0) > 100 * 1024; // 100KB threshold
|
||||
|
||||
// For large messages, process chunks efficiently to avoid memory issues
|
||||
if (isLargeMessage) {
|
||||
session.emailData = this.processEmailDataStreaming(session.emailDataChunks || []);
|
||||
|
||||
// Clear chunks immediately after processing to free memory
|
||||
session.emailDataChunks = [];
|
||||
session.emailDataSize = 0;
|
||||
|
||||
// Force garbage collection for large messages
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
} else {
|
||||
// For smaller messages, use the simpler approach
|
||||
session.emailData = (session.emailDataChunks || []).join('');
|
||||
|
||||
// Remove trailing end-of-data marker: various formats
|
||||
session.emailData = session.emailData
|
||||
.replace(/\r\n\.\r\n$/, '')
|
||||
.replace(/\n\.\r\n$/, '')
|
||||
.replace(/\r\n\.\n$/, '')
|
||||
.replace(/\n\.\n$/, '')
|
||||
.replace(/^\.$/, ''); // Handle ONLY a lone dot as the entire content (not trailing dots)
|
||||
|
||||
// Remove dot-stuffing (RFC 5321, section 4.5.2)
|
||||
session.emailData = session.emailData.replace(/\r\n\.\./g, '\r\n.');
|
||||
|
||||
// Clear chunks after processing
|
||||
session.emailDataChunks = [];
|
||||
}
|
||||
|
||||
public async processEmailLegacy(session: ISmtpSession): Promise<ISmtpTransactionResult> {
|
||||
try {
|
||||
// Parse email into Email object
|
||||
const email = await this.parseEmail(session);
|
||||
// Use the email data from session
|
||||
const email = await this.parseEmailFromData(session.emailData || '', session);
|
||||
|
||||
// Process the email based on the processing mode
|
||||
const processingMode = session.processingMode || 'mta';
|
||||
@@ -1195,6 +1228,18 @@ SmtpLogger.debug(`Parsed email subject: ${subject}`, { subject });
|
||||
}, 100); // Short delay before retry
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle email data (interface requirement)
|
||||
*/
|
||||
public async handleData(
|
||||
socket: plugins.net.Socket | plugins.tls.TLSSocket,
|
||||
data: string,
|
||||
session: ISmtpSession
|
||||
): Promise<void> {
|
||||
// Delegate to existing method
|
||||
await this.handleDataReceived(socket, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources
|
||||
*/
|
||||
|
Reference in New Issue
Block a user