feat: Enhance Nodemailer transport with attachment support and raw message streaming
This commit is contained in:
parent
a89e780165
commit
26d11289ea
2 changed files with 47 additions and 5 deletions
|
@ -16,7 +16,7 @@ async function nodemailerTransportExample() {
|
|||
apiKey: 'cebc9a7f-4e0c-4fda-9dd0-85f48c02800c',
|
||||
port: 80,
|
||||
secure: false, // Set to true for wss://
|
||||
debug: false
|
||||
debug: true
|
||||
});
|
||||
|
||||
// Create Nodemailer transporter
|
||||
|
@ -51,7 +51,15 @@ async function nodemailerTransportExample() {
|
|||
<li>Nodemailer compatibility</li>
|
||||
<li>WebSocket-based SMTP relay</li>
|
||||
</ul>
|
||||
`
|
||||
<p><strong>This email includes a test attachment!</strong></p>
|
||||
`,
|
||||
attachments: [
|
||||
{
|
||||
filename: 'test-attachment.txt',
|
||||
content: Buffer.from(`This is a test attachment generated at ${new Date().toISOString()}\n\nRandom data: ${Math.random()}\nUUID: ${Date.now()}-${Math.random().toString(36).substr(2, 9)}\n\nFeatures tested:\n- File attachment support\n- Binary content handling\n- MIME multipart encoding\n- WebSocket SMTP transport\n\nEnd of test file.`, 'utf8'),
|
||||
contentType: 'text/plain'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
console.log('Email sent successfully!');
|
||||
|
|
|
@ -6,6 +6,7 @@ import { EventEmitter } from 'events';
|
|||
import { SMTPOverWSClient } from './client';
|
||||
import { SMTPClientConfig, ConnectionState } from './types';
|
||||
import { ConnectionError, MessageError, TimeoutError } from './errors';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
/**
|
||||
* Nodemailer transport interface compatibility
|
||||
|
@ -45,7 +46,8 @@ export interface MailMessage {
|
|||
data: any;
|
||||
message: {
|
||||
_envelope: Envelope;
|
||||
_raw: string | Buffer;
|
||||
_raw?: string | Buffer;
|
||||
createReadStream(): Readable;
|
||||
};
|
||||
mailer: any;
|
||||
}
|
||||
|
@ -202,9 +204,11 @@ export class SMTPWSTransport extends EventEmitter {
|
|||
*/
|
||||
private async sendMail(mail: MailMessage): Promise<SendResult> {
|
||||
const envelope = this.extractEnvelope(mail);
|
||||
const raw = mail.message._raw;
|
||||
const messageId = this.generateMessageId();
|
||||
|
||||
// Get the raw message content from Nodemailer's stream
|
||||
const rawMessage = await this.getRawMessage(mail);
|
||||
|
||||
// Build complete SMTP transaction
|
||||
let smtpTransaction = '';
|
||||
|
||||
|
@ -220,7 +224,7 @@ export class SMTPWSTransport extends EventEmitter {
|
|||
smtpTransaction += 'DATA\r\n';
|
||||
|
||||
// Message content
|
||||
const messageData = this.prepareMessageData(raw);
|
||||
const messageData = this.prepareMessageData(rawMessage);
|
||||
smtpTransaction += messageData;
|
||||
|
||||
// QUIT
|
||||
|
@ -337,6 +341,36 @@ export class SMTPWSTransport extends EventEmitter {
|
|||
return `smtp-ws-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw message content from Nodemailer mail object
|
||||
*/
|
||||
private async getRawMessage(mail: MailMessage): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// If raw message is already available, use it
|
||||
if (mail.message._raw) {
|
||||
resolve(mail.message._raw.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, stream the message from Nodemailer
|
||||
const chunks: Buffer[] = [];
|
||||
const stream = mail.message.createReadStream();
|
||||
|
||||
stream.on('data', (chunk: Buffer) => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
const rawMessage = Buffer.concat(chunks).toString();
|
||||
resolve(rawMessage);
|
||||
});
|
||||
|
||||
stream.on('error', (error) => {
|
||||
reject(new MessageError(`Failed to read message stream: ${error.message}`, 'stream-read', 0));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue