mirror of https://github.com/eleith/emailjs.git
lint: enable @typescript-eslint plugin
This commit is contained in:
parent
e6f4cc28fa
commit
9d80365677
|
@ -15,9 +15,19 @@
|
|||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:prettier/recommended"
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": [
|
||||
"error",
|
||||
{
|
||||
"ignoreRestArgs": true
|
||||
}
|
||||
],
|
||||
"curly": [
|
||||
"error",
|
||||
"all"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import addressparser from 'addressparser';
|
||||
import { Message } from './message';
|
||||
import type { MessageAttachment, MessageHeaders } from './message'; // eslint-disable-line no-unused-vars
|
||||
import type { MessageAttachment, MessageHeaders } from './message';
|
||||
import { SMTPConnection, SMTPState } from './smtp';
|
||||
import type { SMTPConnectionOptions } from './smtp'; // eslint-disable-line no-unused-vars
|
||||
import type { SMTPConnectionOptions } from './smtp';
|
||||
|
||||
export interface MessageStack {
|
||||
callback: (error: Error | null, message: Message) => void;
|
||||
|
@ -57,7 +57,12 @@ export class Client {
|
|||
message,
|
||||
to: addressparser(message.header.to),
|
||||
from: addressparser(message.header.from)[0].address,
|
||||
callback: (callback || function () {}).bind(this),
|
||||
callback: (
|
||||
callback ||
|
||||
function () {
|
||||
/* ø */
|
||||
}
|
||||
).bind(this),
|
||||
} as MessageStack;
|
||||
|
||||
if (message.header.cc) {
|
||||
|
@ -241,7 +246,7 @@ export class Client {
|
|||
throw new TypeError('stack.to must be array');
|
||||
}
|
||||
|
||||
const to = stack.to.shift()!.address;
|
||||
const to = stack.to.shift()?.address;
|
||||
this.smtp.rcpt(
|
||||
this._sendsmtp(stack, stack.to.length ? this._sendrcpt : this._senddata),
|
||||
`<${to}>`
|
||||
|
|
|
@ -17,7 +17,7 @@ export const SMTPErrorStates = {
|
|||
|
||||
class SMTPError extends Error {
|
||||
public code: number | null = null;
|
||||
public smtp: any = null;
|
||||
public smtp: unknown = null;
|
||||
public previous: Error | null = null;
|
||||
|
||||
constructor(message: string) {
|
||||
|
@ -29,7 +29,7 @@ export function makeSMTPError(
|
|||
message: string,
|
||||
code: number,
|
||||
error?: Error | null,
|
||||
smtp?: any
|
||||
smtp?: unknown
|
||||
) {
|
||||
const msg = error?.message ? `${message} (${error.message})` : message;
|
||||
const err = new SMTPError(msg);
|
||||
|
|
407
smtp/message.ts
407
smtp/message.ts
|
@ -1,7 +1,8 @@
|
|||
import fs from 'fs';
|
||||
import type { PathLike } from 'fs';
|
||||
import { hostname } from 'os';
|
||||
import { Stream } from 'stream';
|
||||
import type { Duplex } from 'stream'; // eslint-disable-line no-unused-vars
|
||||
import type { Duplex } from 'stream';
|
||||
import addressparser from 'addressparser';
|
||||
import { mimeWordEncode } from 'emailjs-mime-codec';
|
||||
|
||||
|
@ -25,35 +26,44 @@ export const MIME64CHUNK = (MIMECHUNK * 6) as 456;
|
|||
export const BUFFERSIZE = (MIMECHUNK * 24 * 7) as 12768;
|
||||
|
||||
export interface MessageAttachmentHeaders {
|
||||
[index: string]: any;
|
||||
[index: string]: string | undefined;
|
||||
'content-type'?: string;
|
||||
'content-transfer-encoding'?: string;
|
||||
'content-transfer-encoding'?: BufferEncoding | '7bit' | '8bit';
|
||||
'content-disposition'?: string;
|
||||
}
|
||||
|
||||
export interface AlternateMessageAttachment {
|
||||
[index: string]: any;
|
||||
[index: string]:
|
||||
| string
|
||||
| boolean
|
||||
| MessageAttachment
|
||||
| MessageAttachment[]
|
||||
| MessageAttachmentHeaders
|
||||
| Duplex
|
||||
| PathLike
|
||||
| undefined;
|
||||
name?: string;
|
||||
headers?: MessageAttachmentHeaders;
|
||||
inline: boolean;
|
||||
alternative?: MessageAttachment | boolean;
|
||||
related?: MessageAttachment[];
|
||||
data: any;
|
||||
encoded?: any;
|
||||
data: string;
|
||||
encoded?: boolean;
|
||||
stream?: Duplex;
|
||||
path?: PathLike;
|
||||
}
|
||||
|
||||
export interface MessageAttachment extends AlternateMessageAttachment {
|
||||
name: string;
|
||||
type: string;
|
||||
charset: string;
|
||||
method: string;
|
||||
path: string;
|
||||
stream: Duplex;
|
||||
}
|
||||
|
||||
export interface MessageHeaders {
|
||||
[index: string]: any;
|
||||
[index: string]: string | null | MessageAttachment | MessageAttachment[];
|
||||
'content-type': string;
|
||||
'message-id': string;
|
||||
'return-path': string | null;
|
||||
date: string;
|
||||
from: string;
|
||||
to: string;
|
||||
|
@ -64,7 +74,7 @@ export interface MessageHeaders {
|
|||
attachment: MessageAttachment | MessageAttachment[];
|
||||
}
|
||||
|
||||
let counter: number = 0;
|
||||
let counter = 0;
|
||||
|
||||
function generate_boundary() {
|
||||
let text = '';
|
||||
|
@ -95,14 +105,14 @@ function convertDashDelimitedTextToSnakeCase(text: string) {
|
|||
}
|
||||
|
||||
export class Message {
|
||||
public readonly attachments: any[] = [];
|
||||
public readonly attachments: MessageAttachment[] = [];
|
||||
public readonly header: Partial<MessageHeaders> = {
|
||||
'message-id': `<${new Date().getTime()}.${counter++}.${
|
||||
process.pid
|
||||
}@${hostname()}>`,
|
||||
date: getRFC2822Date(),
|
||||
};
|
||||
public readonly content = 'text/plain; charset=utf-8';
|
||||
public readonly content: string = 'text/plain; charset=utf-8';
|
||||
public readonly text?: string;
|
||||
public alternative: AlternateMessageAttachment | null = null;
|
||||
|
||||
|
@ -110,7 +120,7 @@ export class Message {
|
|||
for (const header in headers) {
|
||||
// allow user to override default content-type to override charset or send a single non-text message
|
||||
if (/^content-type$/i.test(header)) {
|
||||
this.content = headers[header];
|
||||
this.content = headers[header] as string;
|
||||
} else if (header === 'text') {
|
||||
this.text = headers[header] as string;
|
||||
} else if (
|
||||
|
@ -129,7 +139,7 @@ export class Message {
|
|||
this.header.subject = mimeWordEncode(headers.subject);
|
||||
} else if (/^(cc|bcc|to|from)/i.test(header)) {
|
||||
this.header[header.toLowerCase()] = convertPersonToAddress(
|
||||
headers[header]
|
||||
headers[header] as string
|
||||
);
|
||||
} else {
|
||||
// allow any headers the user wants to set??
|
||||
|
@ -216,6 +226,7 @@ export class Message {
|
|||
* @returns {*} a stream of the current message
|
||||
*/
|
||||
public stream() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return new MessageStream(this);
|
||||
}
|
||||
|
||||
|
@ -245,51 +256,57 @@ class MessageStream extends Stream {
|
|||
constructor(private message: Message) {
|
||||
super();
|
||||
|
||||
const output_mixed = () => {
|
||||
const boundary = generate_boundary();
|
||||
output(
|
||||
`Content-Type: multipart/mixed; boundary="${boundary}"${CRLF}${CRLF}--${boundary}${CRLF}`
|
||||
);
|
||||
|
||||
if (this.message.alternative == null) {
|
||||
output_text(this.message);
|
||||
output_message(boundary, this.message.attachments, 0, close);
|
||||
} else {
|
||||
output_alternative(
|
||||
// typescript bug; should narrow to { alternative: AlternateMessageAttachment }
|
||||
this.message as Parameters<typeof output_alternative>[0],
|
||||
() => output_message(boundary, this.message.attachments, 0, close)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} boundary the boundary text between outputs
|
||||
* @param {MessageAttachment[]} list the list of potential messages to output
|
||||
* @param {number} index the index of the list item to output
|
||||
* @param {function(): void} callback the function to call if index is greater than upper bound
|
||||
* @param {string} [data] the data to output
|
||||
* @param {Function} [callback] the function
|
||||
* @param {any[]} [args] array of arguments to pass to the callback
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_message = (
|
||||
boundary: string,
|
||||
list: MessageAttachment[],
|
||||
index: number,
|
||||
callback: () => void
|
||||
) => {
|
||||
if (index < list.length) {
|
||||
output(`--${boundary}${CRLF}`);
|
||||
if (list[index].related) {
|
||||
output_related(list[index], () =>
|
||||
output_message(boundary, list, index + 1, callback)
|
||||
);
|
||||
} else {
|
||||
output_attachment(list[index], () =>
|
||||
output_message(boundary, list, index + 1, callback)
|
||||
);
|
||||
const output = (data: string) => {
|
||||
// can we buffer the data?
|
||||
if (this.buffer != null) {
|
||||
const bytes = Buffer.byteLength(data);
|
||||
|
||||
if (bytes + this.bufferIndex < this.buffer.length) {
|
||||
this.buffer.write(data, this.bufferIndex);
|
||||
this.bufferIndex += bytes;
|
||||
}
|
||||
// we can't buffer the data, so ship it out!
|
||||
else if (bytes > this.buffer.length) {
|
||||
if (this.bufferIndex) {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer.toString('utf-8', 0, this.bufferIndex)
|
||||
);
|
||||
this.bufferIndex = 0;
|
||||
}
|
||||
|
||||
const loops = Math.ceil(data.length / this.buffer.length);
|
||||
let loop = 0;
|
||||
while (loop < loops) {
|
||||
this.emit(
|
||||
'data',
|
||||
data.substring(
|
||||
this.buffer.length * loop,
|
||||
this.buffer.length * (loop + 1)
|
||||
)
|
||||
);
|
||||
loop++;
|
||||
}
|
||||
} // we need to clean out the buffer, it is getting full
|
||||
else {
|
||||
if (!this.paused) {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer.toString('utf-8', 0, this.bufferIndex)
|
||||
);
|
||||
this.buffer.write(data, 0);
|
||||
this.bufferIndex = bytes;
|
||||
} else {
|
||||
// we can't empty out the buffer, so let's wait till we resume before adding to it
|
||||
this.once('resume', () => output(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output(`${CRLF}--${boundary}--${CRLF}${CRLF}`);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -309,7 +326,9 @@ class MessageStream extends Stream {
|
|||
'content-transfer-encoding': 'base64',
|
||||
'content-disposition': attachment.inline
|
||||
? 'inline'
|
||||
: `attachment; filename="${mimeWordEncode(attachment.name)}"`,
|
||||
: `attachment; filename="${mimeWordEncode(
|
||||
attachment.name as string
|
||||
)}"`,
|
||||
};
|
||||
|
||||
// allow sender to override default headers
|
||||
|
@ -323,7 +342,7 @@ class MessageStream extends Stream {
|
|||
data = data.concat([
|
||||
convertDashDelimitedTextToSnakeCase(header),
|
||||
': ',
|
||||
headers[header],
|
||||
headers[header] as string,
|
||||
CRLF,
|
||||
]);
|
||||
}
|
||||
|
@ -331,34 +350,21 @@ class MessageStream extends Stream {
|
|||
output(data.concat([CRLF]).join(''));
|
||||
};
|
||||
|
||||
const output_attachment = (
|
||||
attachment: MessageAttachment | AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
const build = attachment.path
|
||||
? output_file
|
||||
: attachment.stream
|
||||
? output_stream
|
||||
: output_data;
|
||||
output_attachment_headers(attachment);
|
||||
build(attachment, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MessageAttachment} attachment the metadata to use as headers
|
||||
* @param {function(): void} callback the function to call after output is finished
|
||||
* @param {string} data the data to output as base64
|
||||
* @param {function(): void} [callback] the function to call after output is finished
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_data = (
|
||||
attachment: MessageAttachment | AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
output_base64(
|
||||
attachment.encoded
|
||||
? attachment.data
|
||||
: Buffer.from(attachment.data).toString('base64'),
|
||||
callback
|
||||
);
|
||||
const output_base64 = (data: string, callback?: () => void) => {
|
||||
const loops = Math.ceil(data.length / MIMECHUNK);
|
||||
let loop = 0;
|
||||
while (loop < loops) {
|
||||
output(data.substring(MIMECHUNK * loop, MIMECHUNK * (loop + 1)) + CRLF);
|
||||
loop++;
|
||||
}
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const output_file = (
|
||||
|
@ -415,7 +421,7 @@ class MessageStream extends Stream {
|
|||
}
|
||||
};
|
||||
|
||||
fs.open(attachment.path, 'r', opened);
|
||||
fs.open(attachment.path as PathLike, 'r', opened);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -427,19 +433,22 @@ class MessageStream extends Stream {
|
|||
attachment: MessageAttachment | AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
if (attachment.stream.readable) {
|
||||
if (attachment.stream != null && attachment.stream.readable) {
|
||||
let previous = Buffer.alloc(0);
|
||||
|
||||
attachment.stream.resume();
|
||||
|
||||
(attachment as MessageAttachment).stream.on('end', () => {
|
||||
attachment.stream.on('end', () => {
|
||||
output_base64(previous.toString('base64'), callback);
|
||||
this.removeListener('pause', attachment.stream.pause);
|
||||
this.removeListener('resume', attachment.stream.resume);
|
||||
this.removeListener('error', attachment.stream.resume);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.removeListener('pause', attachment.stream!.pause);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.removeListener('resume', attachment.stream!.resume);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.removeListener('error', attachment.stream!.resume);
|
||||
});
|
||||
|
||||
(attachment as MessageAttachment).stream.on('data', (buff) => {
|
||||
attachment.stream.on('data', (buff) => {
|
||||
// do we have bytes from a previous stream data event?
|
||||
let buffer = Buffer.isBuffer(buff) ? buff : Buffer.from(buff);
|
||||
|
||||
|
@ -466,23 +475,84 @@ class MessageStream extends Stream {
|
|||
}
|
||||
};
|
||||
|
||||
const output_attachment = (
|
||||
attachment: MessageAttachment | AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
const build = attachment.path
|
||||
? output_file
|
||||
: attachment.stream
|
||||
? output_stream
|
||||
: output_data;
|
||||
output_attachment_headers(attachment);
|
||||
build(attachment, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} data the data to output as base64
|
||||
* @param {function(): void} [callback] the function to call after output is finished
|
||||
* @param {string} boundary the boundary text between outputs
|
||||
* @param {MessageAttachment[]} list the list of potential messages to output
|
||||
* @param {number} index the index of the list item to output
|
||||
* @param {function(): void} callback the function to call if index is greater than upper bound
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_base64 = (data: string, callback?: () => void) => {
|
||||
const loops = Math.ceil(data.length / MIMECHUNK);
|
||||
let loop = 0;
|
||||
while (loop < loops) {
|
||||
output(data.substring(MIMECHUNK * loop, MIMECHUNK * (loop + 1)) + CRLF);
|
||||
loop++;
|
||||
}
|
||||
if (callback) {
|
||||
const output_message = (
|
||||
boundary: string,
|
||||
list: MessageAttachment[],
|
||||
index: number,
|
||||
callback: () => void
|
||||
) => {
|
||||
if (index < list.length) {
|
||||
output(`--${boundary}${CRLF}`);
|
||||
if (list[index].related) {
|
||||
output_related(list[index], () =>
|
||||
output_message(boundary, list, index + 1, callback)
|
||||
);
|
||||
} else {
|
||||
output_attachment(list[index], () =>
|
||||
output_message(boundary, list, index + 1, callback)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
output(`${CRLF}--${boundary}--${CRLF}${CRLF}`);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const output_mixed = () => {
|
||||
const boundary = generate_boundary();
|
||||
output(
|
||||
`Content-Type: multipart/mixed; boundary="${boundary}"${CRLF}${CRLF}--${boundary}${CRLF}`
|
||||
);
|
||||
|
||||
if (this.message.alternative == null) {
|
||||
output_text(this.message);
|
||||
output_message(boundary, this.message.attachments, 0, close);
|
||||
} else {
|
||||
output_alternative(
|
||||
// typescript bug; should narrow to { alternative: AlternateMessageAttachment }
|
||||
this.message as Parameters<typeof output_alternative>[0],
|
||||
() => output_message(boundary, this.message.attachments, 0, close)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MessageAttachment} attachment the metadata to use as headers
|
||||
* @param {function(): void} callback the function to call after output is finished
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_data = (
|
||||
attachment: MessageAttachment | AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
output_base64(
|
||||
attachment.encoded
|
||||
? attachment.data
|
||||
: Buffer.from(attachment.data).toString('base64'),
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Message} message the message to output
|
||||
* @returns {void}
|
||||
|
@ -503,6 +573,27 @@ class MessageStream extends Stream {
|
|||
output(data.join(''));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MessageAttachment} message the message to output
|
||||
* @param {function(): void} callback the function to call after output is finished
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_related = (
|
||||
message: AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
const boundary = generate_boundary();
|
||||
output(
|
||||
`Content-Type: multipart/related; boundary="${boundary}"${CRLF}${CRLF}--${boundary}${CRLF}`
|
||||
);
|
||||
output_attachment(message, () => {
|
||||
output_message(boundary, message.related ?? [], 0, () => {
|
||||
output(`${CRLF}--${boundary}--${CRLF}${CRLF}`);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Message} message the message to output
|
||||
* @param {function(): void} callback the function to call after output is finished
|
||||
|
@ -534,25 +625,24 @@ class MessageStream extends Stream {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MessageAttachment} message the message to output
|
||||
* @param {function(): void} callback the function to call after output is finished
|
||||
* @returns {void}
|
||||
*/
|
||||
const output_related = (
|
||||
message: AlternateMessageAttachment,
|
||||
callback: () => void
|
||||
) => {
|
||||
const boundary = generate_boundary();
|
||||
output(
|
||||
`Content-Type: multipart/related; boundary="${boundary}"${CRLF}${CRLF}--${boundary}${CRLF}`
|
||||
);
|
||||
output_attachment(message, () => {
|
||||
output_message(boundary, message.related ?? [], 0, () => {
|
||||
output(`${CRLF}--${boundary}--${CRLF}${CRLF}`);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
const close = (err?: Error) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
} else {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer?.toString('utf-8', 0, this.bufferIndex) ?? ''
|
||||
);
|
||||
this.emit('end');
|
||||
}
|
||||
this.buffer = null;
|
||||
this.bufferIndex = 0;
|
||||
this.readable = false;
|
||||
this.removeAllListeners('resume');
|
||||
this.removeAllListeners('pause');
|
||||
this.removeAllListeners('error');
|
||||
this.removeAllListeners('data');
|
||||
this.removeAllListeners('end');
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -579,13 +669,12 @@ class MessageStream extends Stream {
|
|||
// do not output BCC in the headers (regex) nor custom Object.prototype functions...
|
||||
if (
|
||||
!/bcc/i.test(header) &&
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
this.message.header.hasOwnProperty(header)
|
||||
Object.prototype.hasOwnProperty.call(this.message.header, header)
|
||||
) {
|
||||
data = data.concat([
|
||||
convertDashDelimitedTextToSnakeCase(header),
|
||||
': ',
|
||||
this.message.header[header],
|
||||
this.message.header[header] as string,
|
||||
CRLF,
|
||||
]);
|
||||
}
|
||||
|
@ -595,80 +684,6 @@ class MessageStream extends Stream {
|
|||
output_header_data();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} [data] the data to output
|
||||
* @param {Function} [callback] the function
|
||||
* @param {any[]} [args] array of arguments to pass to the callback
|
||||
* @returns {void}
|
||||
*/
|
||||
const output = (data: string) => {
|
||||
// can we buffer the data?
|
||||
if (this.buffer != null) {
|
||||
const bytes = Buffer.byteLength(data);
|
||||
|
||||
if (bytes + this.bufferIndex < this.buffer.length) {
|
||||
this.buffer.write(data, this.bufferIndex);
|
||||
this.bufferIndex += bytes;
|
||||
}
|
||||
// we can't buffer the data, so ship it out!
|
||||
else if (bytes > this.buffer.length) {
|
||||
if (this.bufferIndex) {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer.toString('utf-8', 0, this.bufferIndex)
|
||||
);
|
||||
this.bufferIndex = 0;
|
||||
}
|
||||
|
||||
const loops = Math.ceil(data.length / this.buffer.length);
|
||||
let loop = 0;
|
||||
while (loop < loops) {
|
||||
this.emit(
|
||||
'data',
|
||||
data.substring(
|
||||
this.buffer.length * loop,
|
||||
this.buffer.length * (loop + 1)
|
||||
)
|
||||
);
|
||||
loop++;
|
||||
}
|
||||
} // we need to clean out the buffer, it is getting full
|
||||
else {
|
||||
if (!this.paused) {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer.toString('utf-8', 0, this.bufferIndex)
|
||||
);
|
||||
this.buffer.write(data, 0);
|
||||
this.bufferIndex = bytes;
|
||||
} else {
|
||||
// we can't empty out the buffer, so let's wait till we resume before adding to it
|
||||
this.once('resume', () => output(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const close = (err?: any) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
} else {
|
||||
this.emit(
|
||||
'data',
|
||||
this.buffer?.toString('utf-8', 0, this.bufferIndex) ?? ''
|
||||
);
|
||||
this.emit('end');
|
||||
}
|
||||
this.buffer = null;
|
||||
this.bufferIndex = 0;
|
||||
this.readable = false;
|
||||
this.removeAllListeners('resume');
|
||||
this.removeAllListeners('pause');
|
||||
this.removeAllListeners('error');
|
||||
this.removeAllListeners('data');
|
||||
this.removeAllListeners('end');
|
||||
};
|
||||
|
||||
this.once('destroy', close);
|
||||
process.nextTick(output_header);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { makeSMTPError, SMTPErrorStates } from './error';
|
||||
import type { Socket } from 'net'; // eslint-disable-line no-unused-vars
|
||||
import type { TLSSocket } from 'tls'; // eslint-disable-line no-unused-vars
|
||||
import type { Socket } from 'net';
|
||||
import type { TLSSocket } from 'tls';
|
||||
|
||||
export class SMTPResponse {
|
||||
public readonly stop: (err?: Error) => void;
|
||||
|
|
21
smtp/smtp.ts
21
smtp/smtp.ts
|
@ -62,7 +62,7 @@ const log = (...args: any[]) => {
|
|||
*/
|
||||
const caller = (callback?: (...rest: any[]) => void, ...args: any[]) => {
|
||||
if (typeof callback === 'function') {
|
||||
callback.apply(null, args);
|
||||
callback(...args);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -331,7 +331,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @param {*} callback function to call after response
|
||||
* @returns {void}
|
||||
*/
|
||||
public send(str: string, callback: any) {
|
||||
public send(str: string, callback: (...args: any[]) => void) {
|
||||
if (this.sock && this._state === SMTPState.CONNECTED) {
|
||||
this.log(str);
|
||||
|
||||
|
@ -432,7 +432,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @returns {void}
|
||||
*/
|
||||
public starttls(callback: (...rest: any[]) => void) {
|
||||
const response = (err: Error, msg: { data: any }) => {
|
||||
const response = (err: Error, msg: { data: unknown }) => {
|
||||
if (this.sock == null) {
|
||||
throw new Error('null socket');
|
||||
}
|
||||
|
@ -640,7 +640,8 @@ export class SMTPConnection extends EventEmitter {
|
|||
) {
|
||||
// is this code callable...?
|
||||
if (!this.features) {
|
||||
const response = (err: Error, data: any) => caller(callback, err, data);
|
||||
const response = (err: Error, data: unknown) =>
|
||||
caller(callback, err, data);
|
||||
this.ehlo((err, data) => {
|
||||
if (err) {
|
||||
this.helo(response, domain);
|
||||
|
@ -681,7 +682,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
|
||||
const domain = options?.domain || this.domain;
|
||||
|
||||
const initiate = (err: Error | null | undefined, data: any) => {
|
||||
const initiate = (err: Error | null | undefined, data: unknown) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
return;
|
||||
|
@ -742,7 +743,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @param {*} data data
|
||||
* @returns {void}
|
||||
*/
|
||||
const failed = (err: Error, data: any) => {
|
||||
const failed = (err: Error, data: unknown) => {
|
||||
this.loggedin = false;
|
||||
this.close(); // if auth is bad, close the connection, it won't get better by itself
|
||||
caller(
|
||||
|
@ -761,7 +762,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @param {*} data data
|
||||
* @returns {void}
|
||||
*/
|
||||
const response = (err: Error | null | undefined, data: any) => {
|
||||
const response = (err: Error | null | undefined, data: unknown) => {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
|
@ -778,7 +779,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
*/
|
||||
const attempt = (
|
||||
err: Error | null | undefined,
|
||||
data: any,
|
||||
data: unknown,
|
||||
msg: string
|
||||
) => {
|
||||
if (err) {
|
||||
|
@ -802,7 +803,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @param {string} msg msg
|
||||
* @returns {void}
|
||||
*/
|
||||
const attempt_user = (err: Error, data: any) => {
|
||||
const attempt_user = (err: Error, data: unknown) => {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
|
@ -858,7 +859,7 @@ export class SMTPConnection extends EventEmitter {
|
|||
* @param {boolean} [force=false] whether or not to force destroy the connection
|
||||
* @returns {void}
|
||||
*/
|
||||
public close(force: boolean = false) {
|
||||
public close(force = false) {
|
||||
if (this.sock) {
|
||||
if (force) {
|
||||
this.log('smtp connection destroyed!');
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
declare module 'addressparser' {
|
||||
var addressparser: (address?: string) => { name: string; address: string }[];
|
||||
export = addressparser;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Readable } from 'stream'; // eslint-disable-line no-unused-vars
|
||||
import type { Readable } from 'stream';
|
||||
import test from 'ava';
|
||||
import mailparser from 'mailparser';
|
||||
import smtp from 'smtp-server';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Readable } from 'stream'; // eslint-disable-line no-unused-vars
|
||||
import type { Readable } from 'stream';
|
||||
import test from 'ava';
|
||||
import mailparser from 'mailparser';
|
||||
import smtp from 'smtp-server';
|
||||
|
|
|
@ -9,7 +9,7 @@ const toD = (dt: number, utc = false) => getRFC2822Date(new Date(dt), utc);
|
|||
test('rfc2822 non-UTC', async (t) => {
|
||||
// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
|
||||
// thanks to moment.js for the listing: https://github.com/moment/moment/blob/a831fc7e2694281ce31e4f090bbcf90a690f0277/src/lib/create/from-string.js#L101
|
||||
var rfc2822re = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
|
||||
const rfc2822re = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
|
||||
t.regex(toD(0), rfc2822re);
|
||||
t.regex(toD(329629726785), rfc2822re);
|
||||
t.regex(toD(729629726785), rfc2822re);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Readable } from 'stream'; // eslint-disable-line no-unused-vars
|
||||
import type { Readable } from 'stream';
|
||||
import { readFileSync, createReadStream } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
|
|
Loading…
Reference in New Issue