mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2026-10-09 09:59:45 +07:00
node_modules: update (#332)
Co-authored-by: dawidd6 <9713907+dawidd6@users.noreply.github.com>
This commit is contained in:
1 parent
c1dac70e3a
commit
6bf0a2f26a
95 files changed
+1102
-503
No files matched your search
+16
-1
@@ -42,4 +42,19 @@ export type Address = MailboxAddress | GroupAddress;
|
||||
* @param options._depth Internal recursion depth counter (do not set manually)
|
||||
* @return An array of address objects
|
||||
*/
|
||||
export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
|
||||
declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
|
||||
flatten: true;
|
||||
}): MailboxAddress[];
|
||||
declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working
|
||||
*/
|
||||
type AddressEntry = Address;
|
||||
declare namespace addressparser {
|
||||
type Address = MailboxAddress;
|
||||
type Group = GroupAddress;
|
||||
type AddressOrGroup = AddressEntry;
|
||||
}
|
||||
/** The names @types/nodemailer used for the group entry and for the union of both entry types */
|
||||
export type { GroupAddress as Group, Address as AddressOrGroup };
|
||||
export default addressparser;
|
||||
+1
-17
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = addressparser;
|
||||
/**
|
||||
* Restores the quoting of a local part that was read out of a quoted string.
|
||||
*
|
||||
@@ -583,22 +582,6 @@ class Tokenizer {
|
||||
* malicious input that could cause stack overflow.
|
||||
*/
|
||||
const MAX_NESTED_GROUP_DEPTH = 50;
|
||||
/**
|
||||
* Parses structured e-mail addresses from an address field
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 'Name <address@domain>'
|
||||
*
|
||||
* will be converted to
|
||||
*
|
||||
* [{name: 'Name', address: 'address@domain'}]
|
||||
*
|
||||
* @param str Address field
|
||||
* @param options Optional options object
|
||||
* @param options._depth Internal recursion depth counter (do not set manually)
|
||||
* @return An array of address objects
|
||||
*/
|
||||
function addressparser(str, options) {
|
||||
options = options || {};
|
||||
const depth = options._depth || 0;
|
||||
@@ -667,5 +650,6 @@ function addressparser(str, options) {
|
||||
}
|
||||
return parsedAddresses;
|
||||
}
|
||||
exports.default = addressparser;
|
||||
module.exports = exports.default;
|
||||
Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
|
||||
+2
-1
@@ -25,7 +25,8 @@ function encode(buffer) {
|
||||
*/
|
||||
function wrap(str, lineLength) {
|
||||
str = (str || '').toString();
|
||||
lineLength = lineLength || 76;
|
||||
// a negative length would step backwards through the input and never finish
|
||||
lineLength = Math.max(Number(lineLength) || 76, 1);
|
||||
if (str.length <= lineLength) {
|
||||
return str;
|
||||
}
|
||||
|
||||
+13
-1
@@ -30,11 +30,23 @@ declare class DKIM {
|
||||
constructor(options: DKIMOptions);
|
||||
sign(input: Readable | Buffer | string, extraOptions?: DKIMOptions): DKIMSignedStream;
|
||||
}
|
||||
/** The signer options without any key material */
|
||||
export type DKIMOptionalOptions = Omit<DKIMOptions, 'keys' | 'domainName' | 'keySelector' | 'privateKey'>;
|
||||
/** The signer options for a single key given as domainName, keySelector and privateKey */
|
||||
export type DKIMSingleKeyOptions = Omit<DKIMOptions, 'keys'>;
|
||||
/** The signer options for one or more keys given through `keys` */
|
||||
export type DKIMMultipleKeysOptions = DKIMOptionalOptions & {
|
||||
keys: DKIMKey | DKIMKey[];
|
||||
};
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `DKIM.Options` style references keep working
|
||||
*/
|
||||
declare namespace DKIM {
|
||||
type Options = DKIMOptions;
|
||||
type SingleKeyOptions = Omit<DKIMOptions, 'keys'>;
|
||||
type OptionalOptions = DKIMOptionalOptions;
|
||||
type SingleKeyOptions = DKIMSingleKeyOptions;
|
||||
type MultipleKeysOptions = DKIMMultipleKeysOptions;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as DKIM` and `import DKIM = require()` */
|
||||
export type { DKIMOptions as Options, DKIMOptionalOptions as OptionalOptions, DKIMSingleKeyOptions as SingleKeyOptions, DKIMMultipleKeysOptions as MultipleKeysOptions };
|
||||
export default DKIM;
|
||||
+10
-1
@@ -13,7 +13,7 @@ export interface MessageParserHeaderLine {
|
||||
* from the rest of the body. Headers are emitted with the 'headers' event. Message
|
||||
* body is passed on as the resulting stream.
|
||||
*/
|
||||
export default class MessageParser extends Transform {
|
||||
declare class MessageParser extends Transform {
|
||||
lastBytes: Buffer;
|
||||
headersParsed: boolean;
|
||||
headerBytes: number;
|
||||
@@ -37,3 +37,12 @@ export default class MessageParser extends Transform {
|
||||
checkHeaders(data: Buffer): boolean;
|
||||
parseHeaders(): MessageParserHeaderLine[];
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `MessageParser.Header` style references keep working
|
||||
*/
|
||||
declare namespace MessageParser {
|
||||
type Header = MessageParserHeaderLine;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as MessageParser` and `import MessageParser = require()` */
|
||||
export type { MessageParserHeaderLine as Header };
|
||||
export default MessageParser;
|
||||
+10
-1
@@ -17,7 +17,7 @@ export interface RelaxedBodyOptions {
|
||||
* a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
|
||||
* so a line of any length costs constant memory.
|
||||
*/
|
||||
export default class RelaxedBody extends Transform {
|
||||
declare class RelaxedBody extends Transform {
|
||||
bodyHash: crypto.Hash;
|
||||
/** Bytes of the original body seen so far */
|
||||
byteLength: number;
|
||||
@@ -25,3 +25,12 @@ export default class RelaxedBody extends Transform {
|
||||
constructor(options?: RelaxedBodyOptions);
|
||||
updateHash(chunk: Buffer, final?: boolean): void;
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working
|
||||
*/
|
||||
declare namespace RelaxedBody {
|
||||
type Options = RelaxedBodyOptions;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */
|
||||
export type { RelaxedBodyOptions as Options };
|
||||
export default RelaxedBody;
|
||||
+3
-2
@@ -64,9 +64,10 @@ export declare const EFETCH = "EFETCH";
|
||||
/**
|
||||
* An Error together with the properties Nodemailer attaches to the errors it
|
||||
* hands to callers. Every property is optional, the set that is present
|
||||
* depends on where the error originated.
|
||||
* depends on where the error originated. Socket level errors keep the errno
|
||||
* and syscall fields Node.js sets on them.
|
||||
*/
|
||||
export interface NodemailerError extends Error {
|
||||
export interface NodemailerError extends NodeJS.ErrnoException {
|
||||
/** Nodemailer error code, see ERROR_CODES */
|
||||
code?: string | undefined;
|
||||
/** SMTP command that was in flight when the server replied with an error */
|
||||
|
||||
+12
-1
@@ -17,13 +17,14 @@ export interface Cookie {
|
||||
secure?: boolean | undefined;
|
||||
httponly?: boolean | undefined;
|
||||
}
|
||||
type CookieEntry = Cookie;
|
||||
/**
|
||||
* Creates a biskviit cookie jar for managing cookie values in memory
|
||||
*
|
||||
* @constructor
|
||||
* @param [options] Optional options object
|
||||
*/
|
||||
export default class Cookies {
|
||||
declare class Cookies {
|
||||
options: CookiesOptions;
|
||||
cookies: Cookie[];
|
||||
constructor(options?: CookiesOptions);
|
||||
@@ -94,3 +95,13 @@ export default class Cookies {
|
||||
*/
|
||||
getPath(pathname?: string | null): string;
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `Cookies.Cookie` style references keep working
|
||||
*/
|
||||
declare namespace Cookies {
|
||||
type Options = CookiesOptions;
|
||||
type Cookie = CookieEntry;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as Cookies` and `import Cookies = require()` */
|
||||
export type { CookiesOptions as Options };
|
||||
export default Cookies;
|
||||
+11
@@ -48,4 +48,15 @@ declare function nmfetch(url: string, options?: FetchOptions): FetchResponse;
|
||||
declare namespace nmfetch {
|
||||
var Cookies: typeof import("./cookies.js").default;
|
||||
}
|
||||
type CookiesJar = Cookies;
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working
|
||||
*/
|
||||
declare namespace nmfetch {
|
||||
type Options = FetchOptions;
|
||||
type WritableResponse = FetchResponse;
|
||||
type Cookies = CookiesJar;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */
|
||||
export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies };
|
||||
export default nmfetch;
|
||||
+5
-5
@@ -193,14 +193,14 @@ function nmfetch(url, options) {
|
||||
.join('&'));
|
||||
}
|
||||
catch (E) {
|
||||
if (finished) {
|
||||
return undefined;
|
||||
}
|
||||
// the caller attaches its error listener once nmfetch has returned, so
|
||||
// the error is emitted on the next tick and the stream is handed back
|
||||
// the way every other failure is reported
|
||||
finished = true;
|
||||
E.code = errors.EFETCH;
|
||||
E.sourceUrl = url;
|
||||
fetchRes.emit('error', E);
|
||||
return undefined;
|
||||
setImmediate(() => fetchRes.emit('error', E));
|
||||
return fetchRes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+14
-4
@@ -1,6 +1,6 @@
|
||||
import type { Logger } from '../shared/index.js';
|
||||
import type { MimeNodeEnvelope } from '../mime-node/index.js';
|
||||
import type { default as MailMessage, MailMessageData } from '../mailer/mail-message.js';
|
||||
import type MailMessage from '../mailer/mail-message.js';
|
||||
import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions } from '../mailer/index.js';
|
||||
/**
|
||||
* Options for the JSON transport
|
||||
@@ -12,16 +12,23 @@ export interface JSONTransportOptions extends TransportOptions {
|
||||
skipEncoding?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The value the JSON transport hands to the send callback
|
||||
* The value the JSON transport hands to the send callback. M is the type of the message
|
||||
* field: a JSON string by default, the message object itself when skipEncoding is set
|
||||
*/
|
||||
export interface JSONSentMessageInfo extends SentMessageInfo {
|
||||
export interface JSONSentMessageInfo<M = string> extends SentMessageInfo {
|
||||
/** The envelope the message was generated with */
|
||||
envelope: MimeNodeEnvelope;
|
||||
/** Message-ID value of the message */
|
||||
messageId: string;
|
||||
/** The normalized message as a JSON string, or as the object itself when skipEncoding is set */
|
||||
message: string | MailMessageData;
|
||||
message: M;
|
||||
}
|
||||
/**
|
||||
* The value the JSON transport hands to the send callback when skipEncoding is set: the
|
||||
* message field holds the message object. Typed loosely so that a transporter created with
|
||||
* skipEncoding still fits a variable declared with the plain result type
|
||||
*/
|
||||
export type JSONSentMessageObjectInfo = JSONSentMessageInfo<any>;
|
||||
/**
|
||||
* Generates a Transport object to generate JSON output
|
||||
*
|
||||
@@ -50,5 +57,8 @@ declare namespace JSONTransport {
|
||||
type Options = JSONTransportOptions;
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = JSONSentMessageInfo;
|
||||
type SentMessageObjectInfo = JSONSentMessageObjectInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as JSONTransport` and `import JSONTransport = require()` */
|
||||
export type { JSONTransportOptions as Options, SendMailOptions as MailOptions, JSONSentMessageInfo as SentMessageInfo, JSONSentMessageObjectInfo as SentMessageObjectInfo };
|
||||
export default JSONTransport;
|
||||
+2
@@ -83,6 +83,8 @@ class JSONTransport {
|
||||
}
|
||||
delete data.envelope;
|
||||
delete data.normalizedHeaders;
|
||||
// the message field is the object itself with skipEncoding, the
|
||||
// createTransport overload for that option types the result accordingly
|
||||
return done(null, {
|
||||
envelope,
|
||||
messageId,
|
||||
|
||||
+8
-3
@@ -72,6 +72,11 @@ export type MailComposerListHeaderEntry = string | {
|
||||
export interface MailComposerListHeaders {
|
||||
[key: string]: MailComposerListHeaderEntry | (MailComposerListHeaderEntry | MailComposerListHeaderEntry[])[];
|
||||
}
|
||||
/**
|
||||
* Encoding for the non-ascii header values: quoted-printable ('Q', the default) or base64
|
||||
* ('B'). Only the first letter is read, so the short forms work as well
|
||||
*/
|
||||
export type MailComposerTextEncoding = 'quoted-printable' | 'base64' | 'Q' | 'B';
|
||||
/**
|
||||
* Mail options, the message data MailComposer builds the MIME tree from. The address
|
||||
* fields, subject, messageId, date, inReplyTo and references become headers of the root
|
||||
@@ -114,7 +119,7 @@ export interface MailComposerOptions {
|
||||
/** Content-Transfer-Encoding to force for the text/* nodes that do not set their own */
|
||||
encoding?: string | undefined;
|
||||
/** Header string encoding, 'Q' (the default) or 'B', 'quoted-printable' and 'base64' are accepted as well */
|
||||
textEncoding?: string | undefined;
|
||||
textEncoding?: MailComposerTextEncoding | undefined;
|
||||
/** Pregenerated rfc822 message, used as is instead of building one */
|
||||
raw?: MimeNodeContent | undefined;
|
||||
/** Reject content that points to a URL */
|
||||
@@ -129,8 +134,6 @@ export interface MailComposerOptions {
|
||||
baseBoundary?: string | undefined;
|
||||
/** 'win' for CRLF and 'linux' for LF line breaks in the generated message, kept as is when not set */
|
||||
newline?: string | undefined;
|
||||
/** Keep the Bcc header in the generated message, listed for completeness, the transports set it on the message directly */
|
||||
keepBcc?: boolean | undefined;
|
||||
/** Method to normalize header keys for custom caseing */
|
||||
normalizeHeaderKey?: MimeNodeOptions['normalizeHeaderKey'] | undefined;
|
||||
/** 'high', 'normal' or 'low', sets the priority headers, read by the mailer */
|
||||
@@ -166,4 +169,6 @@ declare class MailComposer {
|
||||
declare namespace MailComposer {
|
||||
type Options = MailComposerOptions;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as MailComposer` and `import MailComposer = require()` */
|
||||
export type { MailComposerOptions as Options };
|
||||
export default MailComposer;
|
||||
+36
-24
@@ -4,8 +4,8 @@ import DKIM, { type DKIMOptions } from '../dkim/index.js';
|
||||
import MailMessage, { type MailDefaults, type SendMailOptions } from './mail-message.js';
|
||||
import net from 'node:net';
|
||||
import type { ConnectionOptions } from 'node:tls';
|
||||
import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders } from '../mail-composer/index.js';
|
||||
import type { NodemailerError, ResultCallback } from '../errors.js';
|
||||
import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders, MailComposerTextEncoding } from '../mail-composer/index.js';
|
||||
import type { Callback, NodemailerError, ResultCallback } from '../errors.js';
|
||||
import type { ParsedUrl } from '../shared/url.js';
|
||||
import type { MimeNodeAddress, MimeNodeEnvelope, MimeNodeEnvelopeInput, MimeNodeHeaders, MimeNodeOptions } from '../mime-node/index.js';
|
||||
import type { XOAuth2ProvisionCallback } from '../xoauth2/index.js';
|
||||
@@ -15,9 +15,10 @@ export type { default as MailMessage } from './mail-message.js';
|
||||
* The base shape of the object a transport hands back for a sent message. Every bundled
|
||||
* transport sets the envelope and the Message-ID, the rest depends on the transport.
|
||||
*
|
||||
* The index signature keeps a transport specific field readable through this type, and it
|
||||
* is also what a result type has to inherit to stay assignable to it, so the result type
|
||||
* of a transport outside this package has to extend this interface rather than restate it
|
||||
* The index signature keeps a transport specific field readable through this type, the way
|
||||
* the `any` typed result of @types/nodemailer was, and it is also what a result type has
|
||||
* to inherit to stay assignable to it, so the result type of a transport outside this
|
||||
* package has to extend this interface rather than restate it
|
||||
*/
|
||||
export interface SentMessageInfo {
|
||||
/** The envelope the message was sent with */
|
||||
@@ -33,9 +34,9 @@ export interface SentMessageInfo {
|
||||
/** Last response from the server */
|
||||
response?: string | undefined;
|
||||
/** The generated message, for the transports that hand it back instead of sending it */
|
||||
message?: unknown;
|
||||
message?: any;
|
||||
/** Transport specific fields */
|
||||
[key: string]: unknown;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Callback for sendMail, receives the transport result once the transport has taken the
|
||||
@@ -43,9 +44,11 @@ export interface SentMessageInfo {
|
||||
*/
|
||||
export type SendMailCallback<T = SentMessageInfo> = (err: NodemailerError | null, info: T) => void;
|
||||
/**
|
||||
* Callback for verify(), success is true once the transport accepted the configuration
|
||||
* Callback for verify(), success is true once the transport accepted the configuration.
|
||||
* Declared with a required success value, the way @types/nodemailer declared it, the
|
||||
* error path hands over the error alone
|
||||
*/
|
||||
export type VerifyCallback = (err: NodemailerError | null, success?: true) => void;
|
||||
export type VerifyCallback = Callback<true>;
|
||||
/**
|
||||
* Callback a plugin calls once it is done, an error aborts the send
|
||||
*/
|
||||
@@ -60,21 +63,23 @@ export type PluginFunction<T = SentMessageInfo> = (mail: MailMessage<T>, callbac
|
||||
*/
|
||||
export interface GetSocketOptions {
|
||||
host?: string | undefined;
|
||||
port?: number | string | undefined;
|
||||
port?: number | undefined;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* The result of a getSocket handler, the socket to use for the connection
|
||||
* The result of a getSocket handler, the socket to use for the connection. The object is
|
||||
* merged into the connection options, so it may carry any of those as well
|
||||
*/
|
||||
export interface SocketOptions {
|
||||
/** An established socket, the proxied connection */
|
||||
connection?: net.Socket | undefined;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Receives the socket options from a getSocket handler, or the error that prevented the
|
||||
* connection
|
||||
* Receives the socket options from a getSocket handler, false when a new socket should be
|
||||
* opened, or the error that prevented the connection
|
||||
*/
|
||||
export type GetSocketCallback = (err: NodemailerError | null, socketOptions?: SocketOptions) => void;
|
||||
export type GetSocketCallback = (err: Error | null, socketOptions?: SocketOptions | false) => void;
|
||||
/**
|
||||
* A socket handler. Mail sets one on the transport as getSocket when a proxy is configured,
|
||||
* the SMTP transports call it to get a proxied socket instead of connecting directly
|
||||
@@ -101,9 +106,12 @@ export interface MailMeta {
|
||||
/**
|
||||
* A transport as consumed by Mail: any object with a name, a version and a send method
|
||||
* works, the rest is optional. Mail forwards its close, isIdle and verify calls to the
|
||||
* methods of the same name as they are, so their arguments are up to the transport
|
||||
* methods of the same name as they are, so their arguments are up to the transport.
|
||||
*
|
||||
* D is the options type of the transport, the second type parameter @types/nodemailer
|
||||
* declared on Transport, Transporter and Mail
|
||||
*/
|
||||
export interface Transport<T = SentMessageInfo> {
|
||||
export interface Transport<T = SentMessageInfo, D extends TransportOptions = TransportOptions> {
|
||||
/** Transport name, used for logging */
|
||||
name: string;
|
||||
/** Transport version, used for logging */
|
||||
@@ -119,7 +127,7 @@ export interface Transport<T = SentMessageInfo> {
|
||||
/** Registers an event listener, the transport may emit 'log', 'error', 'idle' and 'clear' */
|
||||
on?(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
/** The Mail object the transport belongs to, set by Mail */
|
||||
mailer?: Mail<T> | undefined;
|
||||
mailer?: Mail<T, D> | undefined;
|
||||
/** Socket handler for a proxied connection, set by Mail when a proxy is configured */
|
||||
getSocket?: GetSocketHandler | undefined;
|
||||
}
|
||||
@@ -150,22 +158,23 @@ export interface TransportOptions {
|
||||
attachDataUrls?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The transporter object createTransport returns, a Mail instance wrapping a transport
|
||||
* The transporter object createTransport returns, a Mail instance wrapping a transport. D
|
||||
* is the options type of the transport, it types the options field of the transporter
|
||||
*/
|
||||
export type Transporter<T = SentMessageInfo> = Mail<T>;
|
||||
export type Transporter<T = SentMessageInfo, D extends TransportOptions = TransportOptions> = Mail<T, D>;
|
||||
/**
|
||||
* Creates an object for exposing the Mail API
|
||||
*
|
||||
* @constructor
|
||||
* @param transporter Transport object instance to pass the mails to
|
||||
*/
|
||||
declare class Mail<out T = SentMessageInfo> extends EventEmitter {
|
||||
options: TransportOptions;
|
||||
declare class Mail<out T = SentMessageInfo, out D extends TransportOptions = TransportOptions> extends EventEmitter {
|
||||
options: D;
|
||||
/** Message defaults given to createTransport, kept public because the DefinitelyTyped typings declared it */
|
||||
_defaults: MailDefaults;
|
||||
meta: Map<string, any>;
|
||||
dkim: DKIM | false;
|
||||
transporter: Transport<T>;
|
||||
transporter: Transport<T, D>;
|
||||
logger: shared.Logger;
|
||||
/** Closes the transport, the pooled SMTP transport closes its connections */
|
||||
close: () => void;
|
||||
@@ -178,7 +187,7 @@ declare class Mail<out T = SentMessageInfo> extends EventEmitter {
|
||||
};
|
||||
/** Socket handler for a proxied connection, set by setupProxy and handed to the transport on the next send */
|
||||
getSocket?: GetSocketHandler | false | undefined;
|
||||
constructor(transporter: Transport<T>, options?: TransportOptions, defaults?: MailDefaults);
|
||||
constructor(transporter: Transport<T, D>, options?: D, defaults?: MailDefaults);
|
||||
use(step: string, plugin: PluginFunction<T>): this;
|
||||
/**
|
||||
* Sends an email using the preselected transport object
|
||||
@@ -213,7 +222,10 @@ declare namespace Mail {
|
||||
type ListHeader = MailComposerListHeaderEntry;
|
||||
type ListHeaders = MailComposerListHeaders;
|
||||
type Envelope = MimeNodeEnvelopeInput;
|
||||
type TextEncoding = NonNullable<SendMailOptions['textEncoding']>;
|
||||
type Connection = SocketOptions;
|
||||
type TextEncoding = MailComposerTextEncoding;
|
||||
type PluginFunction<T = SentMessageInfo> = MailPluginFunction<T>;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as Mail` and `import Mail = require()` */
|
||||
export type { SendMailOptions as Options, MimeNodeAddress as Address, MailComposerAttachment as Attachment, MailComposerAlternative as AttachmentLike, MailComposerAlternative as AmpAttachment, MailComposerIcalEvent as IcalAttachment, MimeNodeHeaders as Headers, MailComposerListHeaderEntry as ListHeader, MailComposerListHeaders as ListHeaders, MimeNodeEnvelopeInput as Envelope, SocketOptions as Connection, MailComposerTextEncoding as TextEncoding };
|
||||
export default Mail;
|
||||
+11
-4
@@ -3,6 +3,7 @@ import type { MailComposerOptions } from '../mail-composer/index.js';
|
||||
import type { DKIMOptions } from '../dkim/index.js';
|
||||
import type { SMTPEnvelopeDsn } from '../smtp-connection/index.js';
|
||||
import type { SMTPTransportAuthOptions } from '../smtp-transport/index.js';
|
||||
import type { SESSendEmailRequest } from '../ses-transport/index.js';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { ResolveContentOptions } from '../shared/index.js';
|
||||
import type Mail from './index.js';
|
||||
@@ -14,6 +15,8 @@ import type { SentMessageInfo } from './index.js';
|
||||
export interface SendMailOptions extends MailComposerOptions {
|
||||
/** DKIM signing options for this message, used instead of the ones of the transporter */
|
||||
dkim?: DKIMOptions | undefined;
|
||||
/** Extra DKIM options for this message, merged over the options of the signer. The SES transport sets skipFields here, the option is not meant for callers */
|
||||
_dkim?: DKIMOptions | undefined;
|
||||
/** Recipients allowed on this message, 0 disables the limit, defaults to 100000 */
|
||||
maxRecipients?: number | undefined;
|
||||
/** SMTP transports: DSN parameters for the envelope, sent when the server supports the DSN extension */
|
||||
@@ -23,9 +26,7 @@ export interface SendMailOptions extends MailComposerOptions {
|
||||
/** SMTP transports: per-message authentication settings, used instead of the transport level auth */
|
||||
auth?: SMTPTransportAuthOptions | undefined;
|
||||
/** SES transport: extra SendEmailCommand parameters merged into the API call */
|
||||
ses?: {
|
||||
[key: string]: unknown;
|
||||
} | undefined;
|
||||
ses?: SESSendEmailRequest | undefined;
|
||||
}
|
||||
/**
|
||||
* Default message fields, the third argument of createTransport. Applied to every message
|
||||
@@ -71,7 +72,13 @@ export interface MailMessageListHeader {
|
||||
export default class MailMessage<T = SentMessageInfo> {
|
||||
mailer: Mail<T>;
|
||||
data: MailMessageData;
|
||||
message: MimeNode | null;
|
||||
/**
|
||||
* The compiled MIME tree. Set once the compile step is done, so it is null while the
|
||||
* 'compile' plugins run and set by the time the 'stream' plugins and the transport see
|
||||
* the message. Declared as always set, the way @types/nodemailer declared it, since the
|
||||
* plugins that read it are the ones that run after it is set
|
||||
*/
|
||||
message: MimeNode;
|
||||
constructor(mailer: Mail<T>, data?: SendMailOptions);
|
||||
resolveContent(data: {
|
||||
[key: string]: any;
|
||||
|
||||
+5
-2
@@ -2,8 +2,8 @@
|
||||
* A header value split into the value token and its parameters, the result of parseHeaderValue
|
||||
*/
|
||||
export interface ParsedHeaderValue {
|
||||
/** The value ahead of the parameters, for example the content type */
|
||||
value: string | false;
|
||||
/** The value ahead of the parameters, for example the content type, an empty string when there is none */
|
||||
value: string;
|
||||
/** Parameter values keyed by lowercase parameter name */
|
||||
params: Record<string, string>;
|
||||
}
|
||||
@@ -25,6 +25,9 @@ export interface EncodedHeaderParam {
|
||||
/** Parameter value of this part */
|
||||
value: string;
|
||||
}
|
||||
/** The names @types/nodemailer used for the two types above */
|
||||
export type HeaderValue = StructuredHeaderValue;
|
||||
export type ParsedHeaderParam = EncodedHeaderParam;
|
||||
/**
|
||||
* Checks if a value is plaintext string (uses only printable 7bit chars)
|
||||
*
|
||||
|
||||
+1
-1
@@ -402,7 +402,7 @@ function buildHeaderParam(key, data, maxLength) {
|
||||
*/
|
||||
function parseHeaderValue(str) {
|
||||
const response = {
|
||||
value: false,
|
||||
value: '',
|
||||
params: {}
|
||||
};
|
||||
// Parameter names come from a caller supplied contentType/contentDisposition. A
|
||||
|
||||
+5
-2
@@ -108,10 +108,11 @@ export interface MimeNodeEnvelope {
|
||||
}
|
||||
/**
|
||||
* Envelope as accepted by setEnvelope. Recipients are collected from to, cc and bcc, any
|
||||
* other field is copied to the envelope as is
|
||||
* other field is copied to the envelope as is. A `from` of false is the null sender of a
|
||||
* bounce message, it is sent as MAIL FROM:<>
|
||||
*/
|
||||
export interface MimeNodeEnvelopeInput {
|
||||
from?: MimeNodeAddressInput | undefined;
|
||||
from?: MimeNodeAddressInput | false | undefined;
|
||||
to?: MimeNodeAddressInput | undefined;
|
||||
cc?: MimeNodeAddressInput | undefined;
|
||||
bcc?: MimeNodeAddressInput | undefined;
|
||||
@@ -327,4 +328,6 @@ declare namespace MimeNode {
|
||||
type Addresses = MimeNodeAddresses;
|
||||
type Envelope = MimeNodeEnvelope;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */
|
||||
export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope };
|
||||
export default MimeNode;
|
||||
+25
-14
@@ -1,10 +1,16 @@
|
||||
import Mail from './mailer/index.js';
|
||||
import type { MailDefaults, SentMessageInfo, Transport, TransportOptions } from './mailer/index.js';
|
||||
import SMTPPool from './smtp-pool/index.js';
|
||||
import type { SMTPPoolOptions, SMTPPoolSentMessageInfo } from './smtp-pool/index.js';
|
||||
import SMTPTransport from './smtp-transport/index.js';
|
||||
import type { SMTPTransportOptions, SMTPSentMessageInfo } from './smtp-transport/index.js';
|
||||
import SendmailTransport from './sendmail-transport/index.js';
|
||||
import type { SendmailTransportOptions, SendmailSentMessageInfo } from './sendmail-transport/index.js';
|
||||
import StreamTransport from './stream-transport/index.js';
|
||||
import type { StreamTransportOptions, StreamSentMessageInfo } from './stream-transport/index.js';
|
||||
import type { JSONTransportOptions, JSONSentMessageInfo } from './json-transport/index.js';
|
||||
import JSONTransport from './json-transport/index.js';
|
||||
import type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo } from './json-transport/index.js';
|
||||
import SESTransport from './ses-transport/index.js';
|
||||
import type { SESTransportOptions, SESSentMessageInfo } from './ses-transport/index.js';
|
||||
/**
|
||||
* Connection details of a service endpoint of an Ethereal test account
|
||||
@@ -43,24 +49,29 @@ export type TransportConfig = SMTPTransportOptions | SMTPPoolOptions | SendmailT
|
||||
* @param defaults Default message fields that are merged into every message
|
||||
* @returns Mail instance wrapping the transport
|
||||
*/
|
||||
export declare function createTransport(transporter: SMTPPoolOptions & {
|
||||
export declare function createTransport(transporter: SMTPPool | (SMTPPoolOptions & {
|
||||
pool: true;
|
||||
}, defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo>;
|
||||
export declare function createTransport(transporter: SendmailTransportOptions & {
|
||||
}), defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions>;
|
||||
export declare function createTransport(transporter: SendmailTransport | (SendmailTransportOptions & {
|
||||
sendmail: true | string;
|
||||
}, defaults?: MailDefaults): Mail<SendmailSentMessageInfo>;
|
||||
export declare function createTransport(transporter: StreamTransportOptions & {
|
||||
}), defaults?: MailDefaults): Mail<SendmailSentMessageInfo, SendmailTransportOptions>;
|
||||
export declare function createTransport(transporter: StreamTransport | (StreamTransportOptions & {
|
||||
streamTransport: true;
|
||||
}, defaults?: MailDefaults): Mail<StreamSentMessageInfo>;
|
||||
}), defaults?: MailDefaults): Mail<StreamSentMessageInfo, StreamTransportOptions>;
|
||||
export declare function createTransport(transporter: JSONTransportOptions & {
|
||||
jsonTransport: true;
|
||||
}, defaults?: MailDefaults): Mail<JSONSentMessageInfo>;
|
||||
export declare function createTransport(transporter: SESTransportOptions & {
|
||||
skipEncoding: true;
|
||||
}, defaults?: MailDefaults): Mail<JSONSentMessageObjectInfo, JSONTransportOptions>;
|
||||
export declare function createTransport(transporter: JSONTransport | (JSONTransportOptions & {
|
||||
jsonTransport: true;
|
||||
}), defaults?: MailDefaults): Mail<JSONSentMessageInfo, JSONTransportOptions>;
|
||||
export declare function createTransport(transporter: SESTransport | (SESTransportOptions & {
|
||||
SES: object;
|
||||
}, defaults?: MailDefaults): Mail<SESSentMessageInfo>;
|
||||
export declare function createTransport<T = SentMessageInfo>(transporter: Transport<T>, defaults?: MailDefaults): Mail<T>;
|
||||
export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo>;
|
||||
export declare function createTransport(transporter?: TransportConfig | Transport<any> | string, defaults?: MailDefaults): Mail<any>;
|
||||
}), defaults?: MailDefaults): Mail<SESSentMessageInfo, SESTransportOptions>;
|
||||
export declare function createTransport(transporter: SMTPTransport, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
|
||||
export declare function createTransport<T = SentMessageInfo, D extends TransportOptions = TransportOptions>(transporter: Transport<T, D>, defaults?: MailDefaults): Mail<T, D>;
|
||||
export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
|
||||
export declare function createTransport(transporter?: TransportConfig | Transport<any, any> | string, defaults?: MailDefaults): Mail<any, any>;
|
||||
/**
|
||||
* Creates a test account from the Ethereal service (https://ethereal.email)
|
||||
*
|
||||
@@ -98,5 +109,5 @@ export type { SMTPTransportOptions, SMTPSentMessageInfo };
|
||||
export type { SMTPPoolOptions, SMTPPoolSentMessageInfo };
|
||||
export type { SendmailTransportOptions, SendmailSentMessageInfo };
|
||||
export type { StreamTransportOptions, StreamSentMessageInfo };
|
||||
export type { JSONTransportOptions, JSONSentMessageInfo };
|
||||
export type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo };
|
||||
export type { SESTransportOptions, SESSentMessageInfo };
|
||||
+1
@@ -205,3 +205,4 @@ const nodemailer = {
|
||||
getTestMessageUrl
|
||||
};
|
||||
exports.default = nodemailer;
|
||||
Object.defineProperty(exports, 'default', { value: exports, enumerable: false, writable: true, configurable: true });
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
export declare const name = "nodemailer";
|
||||
export declare const version = "10.0.10";
|
||||
export declare const version = "10.0.11";
|
||||
export declare const homepage = "https://nodemailer.com/";
|
||||
+1
-1
@@ -3,5 +3,5 @@
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.homepage = exports.version = exports.name = void 0;
|
||||
exports.name = 'nodemailer';
|
||||
exports.version = '10.0.10';
|
||||
exports.version = '10.0.11';
|
||||
exports.homepage = 'https://nodemailer.com/';
|
||||
+2
@@ -15,6 +15,8 @@ export interface QPEncoderOptions {
|
||||
/** Maximum length for lines, set to false to disable wrapping */
|
||||
lineLength?: number | false | undefined;
|
||||
}
|
||||
/** The name @types/nodemailer used for QPEncoderOptions */
|
||||
export type EncoderOptions = QPEncoderOptions;
|
||||
/**
|
||||
* Creates a transform stream for encoding data to Quoted-Printable encoding
|
||||
*
|
||||
|
||||
+10
-1
@@ -10,6 +10,8 @@ const node_stream_1 = require("node:stream");
|
||||
* @param buffer Buffer to convert
|
||||
* @returns Quoted-Printable encoded string
|
||||
*/
|
||||
// the shortest line wrap() can make progress with: a complete =XX sequence and the soft break
|
||||
const MIN_LINE_LENGTH = 4;
|
||||
// usable characters that do not need encoding
|
||||
// https://tools.ietf.org/html/rfc2045#section-6.7
|
||||
const QP_RANGES = [
|
||||
@@ -46,7 +48,9 @@ function encode(buffer) {
|
||||
*/
|
||||
function wrap(str, lineLength) {
|
||||
str = (str || '').toString();
|
||||
lineLength = lineLength || 76;
|
||||
// a line has to hold a complete =XX sequence plus the soft break, shorter lengths
|
||||
// (or a negative one) would loop without consuming input
|
||||
lineLength = Math.max(Number(lineLength) || 76, MIN_LINE_LENGTH);
|
||||
if (str.length <= lineLength) {
|
||||
return str;
|
||||
}
|
||||
@@ -100,6 +104,11 @@ function wrap(str, lineLength) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!line.length) {
|
||||
// the trimming above emptied the line, which only happens for an incomplete
|
||||
// escape at the very end of the input. Take it as is rather than loop on it
|
||||
line = str.substr(pos, lineLength);
|
||||
}
|
||||
if (pos + line.length < len && line.substr(-1) !== '\n') {
|
||||
if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) {
|
||||
line = line.substr(0, line.length - 3);
|
||||
|
||||
+2
@@ -64,4 +64,6 @@ declare namespace SendmailTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SendmailSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SendmailTransport` and `import SendmailTransport = require()` */
|
||||
export type { SendmailTransportOptions as Options, SendMailOptions as MailOptions, SendmailSentMessageInfo as SentMessageInfo };
|
||||
export default SendmailTransport;
|
||||
+33
-1
@@ -21,6 +21,32 @@ export interface SESTransportOptions extends TransportOptions {
|
||||
SendEmailCommand: new (input: any) => unknown;
|
||||
};
|
||||
}
|
||||
/** The SESv2Client shape the transport needs */
|
||||
export type SESTransportClient = SESTransportOptions['SES']['sesClient'];
|
||||
/** The SendEmailCommand constructor shape the transport needs */
|
||||
export type SESTransportSendEmailCommand = SESTransportOptions['SES']['SendEmailCommand'];
|
||||
/**
|
||||
* SendEmailCommand parameters, the shape of the `ses` message option that is merged into
|
||||
* the API call. Any further SendEmailCommandInput field is accepted as well
|
||||
*/
|
||||
export interface SESSendEmailRequest {
|
||||
FromEmailAddress?: string | undefined;
|
||||
Destination?: {
|
||||
ToAddresses?: string[] | undefined;
|
||||
CcAddresses?: string[] | undefined;
|
||||
BccAddresses?: string[] | undefined;
|
||||
} | undefined;
|
||||
ReplyToAddresses?: string[] | undefined;
|
||||
Content?: unknown;
|
||||
EmailTags?: Array<{
|
||||
Name?: string | undefined;
|
||||
Value?: string | undefined;
|
||||
}> | undefined;
|
||||
ConfigurationSetName?: string | undefined;
|
||||
ListManagementOptions?: unknown;
|
||||
FeedbackForwardingEmailAddress?: string | undefined;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
/**
|
||||
* The value the SES transport hands to the send callback
|
||||
*/
|
||||
@@ -47,7 +73,7 @@ declare class SESTransport extends EventEmitter {
|
||||
name: string;
|
||||
version: string;
|
||||
logger: Logger;
|
||||
constructor(options?: SESTransportOptions);
|
||||
constructor(options: SESTransportOptions);
|
||||
getRegion(cb: (err: Error | null, region?: string | false) => void): void;
|
||||
/**
|
||||
* Compiles a mailcomposer message and forwards it to SES
|
||||
@@ -71,5 +97,11 @@ declare namespace SESTransport {
|
||||
type Options = SESTransportOptions;
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SESSentMessageInfo;
|
||||
type SESv2ClientLike = SESTransportClient;
|
||||
type SendEmailCommandConstructorLike = SESTransportSendEmailCommand;
|
||||
type SendEmailRequestLike = SESSendEmailRequest;
|
||||
type MailSesOptions = SESSendEmailRequest;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SESTransport` and `import SESTransport = require()` */
|
||||
export type { SESTransportOptions as Options, SendMailOptions as MailOptions, SESSentMessageInfo as SentMessageInfo, SESTransportClient as SESv2ClientLike, SESTransportSendEmailCommand as SendEmailCommandConstructorLike, SESSendEmailRequest as SendEmailRequestLike, SESSendEmailRequest as MailSesOptions };
|
||||
export default SESTransport;
|
||||
+18
-6
@@ -34,6 +34,8 @@ export interface ResolvedHostname {
|
||||
/** The resolver error when a cached value was used because of it */
|
||||
error?: Error | undefined;
|
||||
}
|
||||
/** The name @types/nodemailer used for ResolvedHostname */
|
||||
export type ResolveHostnameValue = ResolvedHostname;
|
||||
/**
|
||||
* Resolved addresses as stored in the DNS cache
|
||||
*/
|
||||
@@ -83,6 +85,8 @@ export interface LogEntry {
|
||||
[key: string]: any;
|
||||
}
|
||||
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
/** The name @types/nodemailer used for LogLevel */
|
||||
export type LoggerLevel = LogLevel;
|
||||
/**
|
||||
* A logger supplied by the caller, bunyan style. Any object works, a level it does not
|
||||
* implement is routed to one it does, see _logFunc
|
||||
@@ -104,16 +108,24 @@ export interface GetLoggerOptions {
|
||||
/** A bunyan compatible logger, true for the default console logger, false or unset for no logging */
|
||||
logger?: ExternalLogger | boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* A bunyan style log method: a data object followed by a printf style message, or the
|
||||
* message alone
|
||||
*/
|
||||
export interface LogMethod {
|
||||
(data: LogEntry | undefined, message?: string, ...args: any[]): void;
|
||||
(message?: string, ...args: any[]): void;
|
||||
}
|
||||
/**
|
||||
* The bunyan compatible logger interface returned by getLogger
|
||||
*/
|
||||
export interface Logger {
|
||||
trace(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
debug(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
info(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
warn(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
error(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
fatal(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
trace: LogMethod;
|
||||
debug: LogMethod;
|
||||
info: LogMethod;
|
||||
warn: LogMethod;
|
||||
error: LogMethod;
|
||||
fatal: LogMethod;
|
||||
}
|
||||
/**
|
||||
* A parsed data URI
|
||||
|
||||
+4
-2
@@ -377,8 +377,10 @@ const getLogger = (options, defaults) => {
|
||||
}
|
||||
const logger = options.logger === true ? createDefaultLogger(levels) : options.logger;
|
||||
levels.forEach(level => {
|
||||
response[level] = (data, message, ...args) => {
|
||||
(0, exports._logFunc)(logger, level, defaults, data, message, ...args);
|
||||
response[level] = (...args) => {
|
||||
// the bunyan forms: a data object first, or the message alone
|
||||
const data = typeof args[0] === 'string' ? undefined : args.shift();
|
||||
(0, exports._logFunc)(logger, level, defaults, data, ...args);
|
||||
};
|
||||
});
|
||||
return response;
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
* Minimal HTTP/S proxy client
|
||||
*/
|
||||
import net from 'node:net';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback } from '../errors.js';
|
||||
/**
|
||||
* TLS options for connecting to an HTTPS proxy
|
||||
*/
|
||||
@@ -13,7 +13,7 @@ export interface HttpProxyClientOptions {
|
||||
/**
|
||||
* Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it
|
||||
*/
|
||||
export type HttpProxyClientCallback = (err: NodemailerError | null, socket?: net.Socket) => void;
|
||||
export type HttpProxyClientCallback = Callback<net.Socket>;
|
||||
/**
|
||||
* Establishes proxied connection to destinationPort
|
||||
*
|
||||
|
||||
+6
-4
@@ -52,6 +52,8 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
tlsOptions = {};
|
||||
}
|
||||
tlsOptions = tlsOptions || {};
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
// Reject CRLF in the destination before it reaches the CONNECT request line
|
||||
// and Host header. A tainted host/port could otherwise inject additional
|
||||
// request headers into the proxy connection (HTTP request splitting).
|
||||
@@ -59,7 +61,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
if (!destinationPort || /[\r\n]/.test(destinationHost)) {
|
||||
const err = new Error('Invalid proxy destination');
|
||||
err.code = errors.EPROXY;
|
||||
setImmediate(() => callback(err));
|
||||
setImmediate(() => done(err));
|
||||
return;
|
||||
}
|
||||
const proxy = urllib.parse(proxyUrl);
|
||||
@@ -93,7 +95,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
catch (_E) {
|
||||
// ignore
|
||||
}
|
||||
callback(err);
|
||||
done(err);
|
||||
};
|
||||
const timeoutErr = () => {
|
||||
const err = new Error('Proxy socket timed out');
|
||||
@@ -152,12 +154,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
}
|
||||
const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || ''));
|
||||
err.code = errors.EPROXY;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
socket.removeListener('error', tempSocketErr);
|
||||
socket.removeListener('timeout', timeoutErr);
|
||||
socket.setTimeout(0);
|
||||
return callback(null, socket);
|
||||
return done(null, socket);
|
||||
}
|
||||
if (headers.length > MAX_RESPONSE_HEADER_BYTES) {
|
||||
socket.removeListener('data', onSocketData);
|
||||
|
||||
+57
-22
@@ -3,8 +3,9 @@ import net from 'node:net';
|
||||
import tls from 'node:tls';
|
||||
import { type Readable } from 'node:stream';
|
||||
import * as shared from '../shared/index.js';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback, NodemailerError } from '../errors.js';
|
||||
import type XOAuth2 from '../xoauth2/index.js';
|
||||
import type { XOAuth2Options } from '../xoauth2/index.js';
|
||||
/**
|
||||
* Custom authentication handlers keyed by (case insensitive) SASL method name
|
||||
*/
|
||||
@@ -117,12 +118,23 @@ export interface SMTPConnectionCustomAuthResponse {
|
||||
* Callback for a command sent by a custom authentication handler
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthCommandCallback = (err: Error | null, data: SMTPConnectionCustomAuthResponse) => void;
|
||||
/**
|
||||
* The auth object as a custom authentication handler sees it: the object handed to login()
|
||||
* with the credentials filled in from its user and pass values
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthData extends SMTPConnectionAuth {
|
||||
/** The user and pass values of the auth object, the way @types/nodemailer declared them */
|
||||
credentials: SMTPConnectionCredentials & {
|
||||
user: string;
|
||||
pass: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* The object a custom authentication handler is run with
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthContext {
|
||||
/** The auth object handed to login() */
|
||||
auth: SMTPConnectionAuth;
|
||||
/** The auth object handed to login(), with the credentials filled in */
|
||||
auth: SMTPConnectionCustomAuthData;
|
||||
/** Selected authentication method name */
|
||||
method: string;
|
||||
/** SMTP extensions the server advertised */
|
||||
@@ -131,17 +143,20 @@ export interface SMTPConnectionCustomAuthContext {
|
||||
authMethods: string[];
|
||||
/** Maximum message size the server accepts, false when not advertised */
|
||||
maxAllowedSize: number | false;
|
||||
/** Sends a command to the server. Returns a promise when no callback is given */
|
||||
sendCommand(cmd: string, done?: SMTPConnectionCustomAuthCommandCallback): Promise<SMTPConnectionCustomAuthResponse> | undefined;
|
||||
/** Sends a command to the server and resolves with the parsed reply */
|
||||
sendCommand(cmd: string): Promise<SMTPConnectionCustomAuthResponse>;
|
||||
/** Sends a command to the server and hands the parsed reply to the callback */
|
||||
sendCommand(cmd: string, done: SMTPConnectionCustomAuthCommandCallback): void;
|
||||
/** Marks the user as authenticated */
|
||||
resolve(): void;
|
||||
/** Fails the authentication with an error */
|
||||
reject(err: Error | string): void;
|
||||
}
|
||||
/**
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a promise
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a
|
||||
* promise that settles the authentication. Any other return value is ignored
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => void | Promise<unknown>;
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => unknown;
|
||||
/**
|
||||
* An envelope address, either a plain string or an object with an address property
|
||||
*/
|
||||
@@ -168,12 +183,16 @@ export interface SMTPEnvelopeDsn {
|
||||
/** Alias of recipient, in the 'rfc822;address' form */
|
||||
orcpt?: string | null | undefined;
|
||||
}
|
||||
/**
|
||||
* A single DSN notify value
|
||||
*/
|
||||
export type SMTPEnvelopeDsnNotify = 'NEVER' | 'SUCCESS' | 'FAILURE' | 'DELAY';
|
||||
/**
|
||||
* Envelope object accepted by send()
|
||||
*/
|
||||
export interface SMTPEnvelope {
|
||||
/** Sender address */
|
||||
from?: string | SMTPEnvelopeAddress | undefined;
|
||||
/** Sender address, false for the null sender of a bounce message (MAIL FROM:<>) */
|
||||
from?: string | SMTPEnvelopeAddress | false | undefined;
|
||||
/** Recipient address or addresses */
|
||||
to?: string | SMTPEnvelopeAddress | Array<string | SMTPEnvelopeAddress> | undefined;
|
||||
/** Message size in bytes, sent as the SIZE parameter when the server supports it */
|
||||
@@ -202,9 +221,9 @@ export interface SMTPConnectionEnvelope extends SMTPEnvelope {
|
||||
accepted: string[];
|
||||
}
|
||||
/**
|
||||
* Result of a sent message
|
||||
* The recipient bookkeeping of a sent message, known once the envelope is accepted
|
||||
*/
|
||||
export interface SMTPConnectionSendInfo {
|
||||
export interface SMTPConnectionEnvelopeInfo {
|
||||
/** Recipients the server accepted */
|
||||
accepted: string[];
|
||||
/** Recipients the server rejected */
|
||||
@@ -213,19 +232,25 @@ export interface SMTPConnectionSendInfo {
|
||||
ehlo?: string[] | undefined;
|
||||
/** Errors for the rejected recipients */
|
||||
rejectedErrors?: NodemailerError[] | undefined;
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime?: number | undefined;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime?: number | undefined;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize?: number | undefined;
|
||||
/** Final server response for the message */
|
||||
response?: string | undefined;
|
||||
}
|
||||
/**
|
||||
* Callback for send()
|
||||
* Result of a sent message
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = (err: NodemailerError | null, info?: SMTPConnectionSendInfo) => void;
|
||||
export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo {
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime: number;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime: number;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize: number;
|
||||
/** Final server response for the message */
|
||||
response: string;
|
||||
}
|
||||
/**
|
||||
* Callback for send(), receives the result once the server accepted the message. The error
|
||||
* path hands over the error alone
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = Callback<SMTPConnectionSendInfo>;
|
||||
/**
|
||||
* Callback for login() and reset(), the result is true on success
|
||||
*/
|
||||
@@ -285,7 +310,7 @@ export type SMTPConnectionResponseAction = (str: string) => void;
|
||||
*/
|
||||
declare class SMTPConnection extends EventEmitter {
|
||||
id: string;
|
||||
stage: string;
|
||||
stage: 'init' | 'connected';
|
||||
options: SMTPConnectionOptions;
|
||||
secureConnection: boolean;
|
||||
alreadySecured: boolean;
|
||||
@@ -370,12 +395,22 @@ declare class SMTPConnection extends EventEmitter {
|
||||
declare namespace SMTPConnection {
|
||||
type Options = SMTPConnectionOptions;
|
||||
type AuthenticationType = SMTPConnectionAuth;
|
||||
type AuthenticationTypeLogin = SMTPConnectionAuth;
|
||||
type AuthenticationTypeOAuth2 = SMTPConnectionAuth;
|
||||
type AuthenticationTypeCustom = SMTPConnectionAuth;
|
||||
type AuthenticationCredentials = SMTPConnectionAuth;
|
||||
type AuthenticationOAuth2 = SMTPConnectionAuth;
|
||||
type Credentials = SMTPConnectionCredentials;
|
||||
type OAuth2 = XOAuth2Options;
|
||||
type Envelope = SMTPEnvelope;
|
||||
type DSNOptions = SMTPEnvelopeDsn;
|
||||
type DSNOption = SMTPEnvelopeDsnNotify;
|
||||
type SentMessageInfo = SMTPConnectionSendInfo;
|
||||
type SMTPError = NodemailerError;
|
||||
type CustomAuthenticationContext = SMTPConnectionCustomAuthContext;
|
||||
type CustomAuthenticationResponse = SMTPConnectionCustomAuthResponse;
|
||||
type CustomAuthenticationHandlers = SMTPConnectionCustomAuthHandlers;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPConnection` and `import SMTPConnection = require()` */
|
||||
export type { SMTPConnectionOptions as Options, SMTPConnectionAuth as AuthenticationType, SMTPConnectionAuth as AuthenticationTypeLogin, SMTPConnectionAuth as AuthenticationTypeOAuth2, SMTPConnectionAuth as AuthenticationTypeCustom, SMTPConnectionAuth as AuthenticationCredentials, SMTPConnectionAuth as AuthenticationOAuth2, SMTPConnectionCredentials as Credentials, XOAuth2Options as OAuth2, SMTPEnvelope as Envelope, SMTPEnvelopeDsn as DSNOptions, SMTPEnvelopeDsnNotify as DSNOption, SMTPConnectionSendInfo as SentMessageInfo, NodemailerError as SMTPError, SMTPConnectionCustomAuthContext as CustomAuthenticationContext, SMTPConnectionCustomAuthResponse as CustomAuthenticationResponse, SMTPConnectionCustomAuthHandlers as CustomAuthenticationHandlers };
|
||||
export default SMTPConnection;
|
||||
+68
-55
@@ -452,14 +452,21 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
this._auth = authData || {};
|
||||
// Select SASL authentication method
|
||||
this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
|
||||
// XOAUTH2 needs a token generator or a custom handler, without either the method
|
||||
// can not be run even when it is the only one the server advertised
|
||||
const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2');
|
||||
if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) {
|
||||
this._authMethod = 'XOAUTH2';
|
||||
}
|
||||
else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) {
|
||||
// use first supported
|
||||
this._authMethod = (this._supportedAuth[0] || 'PLAIN').toUpperCase().trim();
|
||||
// use the first supported method that can be run
|
||||
const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2);
|
||||
this._authMethod = (supported || 'PLAIN').toUpperCase().trim();
|
||||
}
|
||||
if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
// a token login needs no credentials, every other method and every custom handler
|
||||
// gets them filled in from the user and pass values
|
||||
if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) &&
|
||||
(!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) {
|
||||
this._auth.credentials = {
|
||||
user: this._auth.user,
|
||||
@@ -496,42 +503,45 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
returned = true;
|
||||
callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod));
|
||||
};
|
||||
// one implementation serves both sendCommand overloads, the promise is returned
|
||||
// exactly when no callback was given
|
||||
const sendCommand = (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
};
|
||||
const handlerResponse = handler({
|
||||
auth: this._auth,
|
||||
method: this._authMethod,
|
||||
extensions: [].concat(this._supportedExtensions),
|
||||
authMethods: [].concat(this._supportedAuth),
|
||||
maxAllowedSize: this._maxAllowedSize || false,
|
||||
sendCommand: (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
},
|
||||
sendCommand: sendCommand,
|
||||
resolve,
|
||||
reject
|
||||
});
|
||||
@@ -588,29 +598,30 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
* @param callback Callback to return once sending is completed
|
||||
*/
|
||||
send(envelope, message, done) {
|
||||
if (!message) {
|
||||
return done(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return done(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
done(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
// ensure that callback is only called once
|
||||
// ensure that the callback is only called once. The public callback type has a
|
||||
// required result, the error paths hand over the error alone
|
||||
let returned = false;
|
||||
const callback = function (...args) {
|
||||
const callback = (err, info) => {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
done(...args);
|
||||
done(err, info);
|
||||
};
|
||||
if (!message) {
|
||||
return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof message.on === 'function') {
|
||||
message.on('error', err => callback(this._formatError(err, 'ESTREAM', false, 'API')));
|
||||
}
|
||||
@@ -633,11 +644,13 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
info.envelopeTime = envelopeTime - startTime;
|
||||
info.messageTime = Date.now() - envelopeTime;
|
||||
info.messageSize = stream.outByteCount;
|
||||
info.response = str;
|
||||
return callback(null, info);
|
||||
// the envelope info becomes the send result once the timings are on it
|
||||
const result = info;
|
||||
result.envelopeTime = envelopeTime - startTime;
|
||||
result.messageTime = Date.now() - envelopeTime;
|
||||
result.messageSize = stream.outByteCount;
|
||||
result.response = str;
|
||||
return callback(null, result);
|
||||
});
|
||||
if (typeof message.pipe === 'function') {
|
||||
message.pipe(stream);
|
||||
|
||||
+4
-2
@@ -80,7 +80,7 @@ declare class SMTPPool extends EventEmitter {
|
||||
/**
|
||||
* The Mail instance using this transport, assigned by Mail
|
||||
*/
|
||||
mailer?: Mail<SMTPPoolSentMessageInfo> | undefined;
|
||||
mailer?: Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions> | undefined;
|
||||
constructor(options?: SMTPPoolOptions | string);
|
||||
/**
|
||||
* Placeholder function for creating proxy sockets. This method immediatelly returns
|
||||
@@ -96,7 +96,7 @@ declare class SMTPPool extends EventEmitter {
|
||||
* @param mail Mail object
|
||||
* @param callback Callback function
|
||||
*/
|
||||
send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean;
|
||||
send(mail: MailMessage<SMTPPoolSentMessageInfo>, callback: SMTPPoolSendCallback): boolean;
|
||||
/**
|
||||
* Closes all connections in the pool. If there is a message being sent, the connection
|
||||
* is closed later
|
||||
@@ -122,4 +122,6 @@ declare namespace SMTPPool {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SMTPPoolSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPPool` and `import SMTPPool = require()` */
|
||||
export type { SMTPPoolOptions as Options, SendMailOptions as MailOptions, SMTPPoolSentMessageInfo as SentMessageInfo };
|
||||
export default SMTPPool;
|
||||
+8
-6
@@ -462,10 +462,12 @@ class SMTPPool extends node_events_1.EventEmitter {
|
||||
callback = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
const auth = new pool_resource_js_1.default(this).auth;
|
||||
this.getSocket(this.options, (err, socketOptions) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
let options = this.options;
|
||||
if (socketOptions && socketOptions.connection) {
|
||||
@@ -487,14 +489,14 @@ class SMTPPool extends node_events_1.EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
connection.once('end', () => {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
return callback(new Error('Connection closed'));
|
||||
return done(new Error('Connection closed'));
|
||||
});
|
||||
const finalize = () => {
|
||||
if (returned) {
|
||||
@@ -502,7 +504,7 @@ class SMTPPool extends node_events_1.EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
connection.quit();
|
||||
return callback(null, true);
|
||||
return done(null, true);
|
||||
};
|
||||
connection.connect(() => {
|
||||
if (returned) {
|
||||
@@ -516,7 +518,7 @@ class SMTPPool extends node_events_1.EventEmitter {
|
||||
if (err) {
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
finalize();
|
||||
});
|
||||
@@ -526,7 +528,7 @@ class SMTPPool extends node_events_1.EventEmitter {
|
||||
err.code = errors.ENOAUTH;
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
else {
|
||||
finalize();
|
||||
|
||||
+1
-3
@@ -138,9 +138,7 @@ class PoolResource extends node_events_1.EventEmitter {
|
||||
}
|
||||
// still have not returned, this means we have an unexpected connection close
|
||||
const err = new Error('Unexpected socket close');
|
||||
if (this.connection &&
|
||||
this.connection._socket &&
|
||||
this.connection._socket.upgrading) {
|
||||
if (this.connection && this.connection.upgrading) {
|
||||
// starttls connection errors
|
||||
err.code = errors.ETLS;
|
||||
}
|
||||
|
||||
+13
-5
@@ -4,7 +4,7 @@ import * as shared from '../shared/index.js';
|
||||
import { type XOAuth2Options } from '../xoauth2/index.js';
|
||||
import type { ResultCallback } from '../errors.js';
|
||||
import type MailMessage from '../mailer/mail-message.js';
|
||||
import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
|
||||
import type { default as Mail, GetSocketCallback, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
|
||||
import type { MimeNodeEnvelope } from '../mime-node/index.js';
|
||||
/**
|
||||
* Authentication settings, either from the transport options or from the message data.
|
||||
@@ -38,9 +38,10 @@ export interface SMTPTransportAuth extends SMTPConnectionAuth {
|
||||
/**
|
||||
* Receives the socket details from getSocket, false when a new socket should be opened. The
|
||||
* object is merged into the connection options, a proxy handler provides the connected socket
|
||||
* as `connection`
|
||||
* as `connection`. The same callback type Mail hands to a transport, so that the SMTP
|
||||
* transports stay assignable to the Transport interface
|
||||
*/
|
||||
export type SMTPTransportGetSocketCallback = (err: Error | null, socketOptions?: SMTPConnectionOptions | false) => void;
|
||||
export type SMTPTransportGetSocketCallback = GetSocketCallback;
|
||||
/**
|
||||
* Custom socket provider, replaces the getSocket method of the transport
|
||||
*/
|
||||
@@ -78,6 +79,8 @@ export interface SMTPSentMessageInfo extends SMTPConnectionSendInfo, SentMessage
|
||||
accepted: string[];
|
||||
/** Recipients the server rejected */
|
||||
rejected: string[];
|
||||
/** Final server response for the message */
|
||||
response: string;
|
||||
}
|
||||
/**
|
||||
* Callback for send()
|
||||
@@ -101,7 +104,7 @@ declare class SMTPTransport extends EventEmitter {
|
||||
/**
|
||||
* The Mail instance using this transport, assigned by Mail
|
||||
*/
|
||||
mailer?: Mail<SMTPSentMessageInfo> | undefined;
|
||||
mailer?: Mail<SMTPSentMessageInfo, SMTPTransportOptions> | undefined;
|
||||
constructor(options?: SMTPTransportOptions | string);
|
||||
/**
|
||||
* Placeholder function for creating proxy sockets. This method immediatelly returns
|
||||
@@ -118,7 +121,7 @@ declare class SMTPTransport extends EventEmitter {
|
||||
* @param mail Mail object
|
||||
* @param callback Callback function
|
||||
*/
|
||||
send(mail: MailMessage, callback: SMTPTransportSendCallback): void;
|
||||
send(mail: MailMessage<SMTPSentMessageInfo>, callback: SMTPTransportSendCallback): void;
|
||||
/**
|
||||
* Verifies SMTP configuration
|
||||
*
|
||||
@@ -139,5 +142,10 @@ declare namespace SMTPTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SMTPSentMessageInfo;
|
||||
type AuthenticationType = SMTPTransportAuth;
|
||||
type AuthenticationTypeLogin = SMTPTransportAuth;
|
||||
type AuthenticationTypeOAuth2 = SMTPTransportAuth;
|
||||
type AuthenticationTypeCustom = SMTPTransportAuth;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPTransport` and `import SMTPTransport = require()` */
|
||||
export type { SMTPTransportOptions as Options, SendMailOptions as MailOptions, SMTPSentMessageInfo as SentMessageInfo, SMTPTransportAuth as AuthenticationType, SMTPTransportAuth as AuthenticationTypeLogin, SMTPTransportAuth as AuthenticationTypeOAuth2, SMTPTransportAuth as AuthenticationTypeCustom };
|
||||
export default SMTPTransport;
|
||||
+9
-7
@@ -189,7 +189,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
cleanupPerCallAuth();
|
||||
// still have not returned, this means we have an unexpected connection close
|
||||
const err = new Error('Unexpected socket close');
|
||||
if (connection && connection._socket && connection._socket.upgrading) {
|
||||
if (connection && connection.upgrading) {
|
||||
// starttls connection errors
|
||||
err.code = errors.ETLS;
|
||||
}
|
||||
@@ -279,9 +279,11 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
callback = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
this.getSocket(this.options, (err, socketOptions) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
let options = this.options;
|
||||
if (socketOptions && socketOptions.connection) {
|
||||
@@ -311,7 +313,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
connection.once('end', () => {
|
||||
if (returned) {
|
||||
@@ -319,7 +321,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
return callback(new Error('Connection closed'));
|
||||
return done(new Error('Connection closed'));
|
||||
});
|
||||
const finalize = () => {
|
||||
if (returned) {
|
||||
@@ -328,7 +330,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.quit();
|
||||
return callback(null, true);
|
||||
return done(null, true);
|
||||
};
|
||||
connection.connect(() => {
|
||||
if (returned) {
|
||||
@@ -344,7 +346,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
if (err) {
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
finalize();
|
||||
});
|
||||
@@ -355,7 +357,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
else {
|
||||
finalize();
|
||||
|
||||
+2
@@ -60,4 +60,6 @@ declare namespace StreamTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = StreamSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as StreamTransport` and `import StreamTransport = require()` */
|
||||
export type { StreamTransportOptions as Options, SendMailOptions as MailOptions, StreamSentMessageInfo as SentMessageInfo };
|
||||
export default StreamTransport;
|
||||
+11
-3
@@ -1,6 +1,7 @@
|
||||
import { Stream } from 'node:stream';
|
||||
import crypto from 'node:crypto';
|
||||
import * as shared from '../shared/index.js';
|
||||
import type { ResultCallback } from '../errors.js';
|
||||
import type { OutgoingHttpHeaders } from 'node:http';
|
||||
/**
|
||||
* Receives the result of a provisionCallback run: an error, or the new access token and
|
||||
@@ -13,9 +14,11 @@ export type XOAuth2ProvisionResultCallback = (err: Error | null, accessToken?: s
|
||||
*/
|
||||
export type XOAuth2ProvisionCallback = (user: string, renew: boolean, callback: XOAuth2ProvisionResultCallback) => void;
|
||||
/**
|
||||
* Receives an access token, or the error that prevented generating one
|
||||
* Receives an access token, or the error that prevented generating one. Declared with a
|
||||
* required token, the way @types/nodemailer declared it, the error path hands over the
|
||||
* error alone
|
||||
*/
|
||||
export type XOAuth2TokenCallback = (err: Error | null, accessToken?: string) => void;
|
||||
export type XOAuth2TokenCallback = (err: Error | null, accessToken: string) => void;
|
||||
/**
|
||||
* A private key accepted by crypto.createSign().sign()
|
||||
*/
|
||||
@@ -79,7 +82,7 @@ export interface XOAuth2Token {
|
||||
*/
|
||||
export interface XOAuth2QueuedRequest {
|
||||
renew: boolean;
|
||||
callback: XOAuth2TokenCallback;
|
||||
callback: ResultCallback<string>;
|
||||
}
|
||||
/**
|
||||
* XOAUTH2 access_token generator for Gmail.
|
||||
@@ -181,11 +184,16 @@ declare class XOAuth2 extends Stream {
|
||||
[key: string]: any;
|
||||
}): string;
|
||||
}
|
||||
/** The extra request settings of the token request, the customHeaders and customParams options */
|
||||
export type XOAuth2RequestParams = Pick<XOAuth2Options, 'customHeaders' | 'customParams'>;
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `XOAuth2.Options` style references keep working
|
||||
*/
|
||||
declare namespace XOAuth2 {
|
||||
type Options = XOAuth2Options;
|
||||
type Token = XOAuth2Token;
|
||||
type RequestParams = XOAuth2RequestParams;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as XOAuth2` and `import XOAuth2 = require()` */
|
||||
export type { XOAuth2Options as Options, XOAuth2Token as Token, XOAuth2RequestParams as RequestParams };
|
||||
export default XOAuth2;
|
||||
+14
-10
@@ -111,6 +111,8 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
* @param callback Callback function with error object and token string
|
||||
*/
|
||||
getToken(renew, callback) {
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) {
|
||||
this.logger.debug({
|
||||
tnx: 'OAUTH2',
|
||||
@@ -136,11 +138,11 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
}, 'Cannot renew access token for %s: No refresh mechanism available', this.options.user);
|
||||
const err = new Error("Can't create new access token for user");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
// If renewal already in progress, queue this request instead of starting another
|
||||
if (this.renewing) {
|
||||
this.renewalQueue.push({ renew, callback });
|
||||
this.renewalQueue.push({ renew, callback: done });
|
||||
return;
|
||||
}
|
||||
this.renewing = true;
|
||||
@@ -165,7 +167,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
}, 'Generated new Access Token for %s', this.options.user);
|
||||
}
|
||||
// Complete original request
|
||||
callback(err, accessToken);
|
||||
done(err, accessToken);
|
||||
};
|
||||
if (this.provisionCallback) {
|
||||
this.provisionCallback(this.options.user, !!renew, (err, accessToken, expires) => {
|
||||
@@ -204,6 +206,8 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
* @param callback Callback function with error object and token string
|
||||
*/
|
||||
generateToken(callback) {
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
let urlOptions;
|
||||
let loggedUrlOptions;
|
||||
if (this.options.serviceClient) {
|
||||
@@ -224,7 +228,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
catch (_err) {
|
||||
const err = new Error("Can't generate token. Check your auth options");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
urlOptions = {
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||||
@@ -239,7 +243,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
if (!this.options.refreshToken) {
|
||||
const err = new Error("Can't create new access token for user");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
// web app - https://developers.google.com/identity/protocols/OAuth2WebServer
|
||||
urlOptions = {
|
||||
@@ -265,13 +269,13 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
this.postRequest(this.options.accessUrl, urlOptions, this.options, (error, body) => {
|
||||
let data;
|
||||
if (error) {
|
||||
return callback(error);
|
||||
return done(error);
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(body.toString());
|
||||
}
|
||||
catch (E) {
|
||||
return callback(E);
|
||||
return done(E);
|
||||
}
|
||||
if (!data || typeof data !== 'object') {
|
||||
this.logger.debug({
|
||||
@@ -281,7 +285,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
}, 'Response: %s', (body || '').toString());
|
||||
const err = new Error('Invalid authentication response');
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
const logData = Object.assign({}, data);
|
||||
if (logData.access_token) {
|
||||
@@ -303,7 +307,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
}
|
||||
const err = new Error(errorMessage);
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
if (data.access_token) {
|
||||
this.updateToken(data.access_token, data.expires_in);
|
||||
@@ -311,7 +315,7 @@ class XOAuth2 extends node_stream_1.Stream {
|
||||
}
|
||||
const err = new Error('No access token');
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
||||
+16
-1
@@ -42,4 +42,19 @@ export type Address = MailboxAddress | GroupAddress;
|
||||
* @param options._depth Internal recursion depth counter (do not set manually)
|
||||
* @return An array of address objects
|
||||
*/
|
||||
export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
|
||||
declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
|
||||
flatten: true;
|
||||
}): MailboxAddress[];
|
||||
declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working
|
||||
*/
|
||||
type AddressEntry = Address;
|
||||
declare namespace addressparser {
|
||||
type Address = MailboxAddress;
|
||||
type Group = GroupAddress;
|
||||
type AddressOrGroup = AddressEntry;
|
||||
}
|
||||
/** The names @types/nodemailer used for the group entry and for the union of both entry types */
|
||||
export type { GroupAddress as Group, Address as AddressOrGroup };
|
||||
export default addressparser;
|
||||
+2
-17
@@ -580,23 +580,7 @@ class Tokenizer {
|
||||
* malicious input that could cause stack overflow.
|
||||
*/
|
||||
const MAX_NESTED_GROUP_DEPTH = 50;
|
||||
/**
|
||||
* Parses structured e-mail addresses from an address field
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 'Name <address@domain>'
|
||||
*
|
||||
* will be converted to
|
||||
*
|
||||
* [{name: 'Name', address: 'address@domain'}]
|
||||
*
|
||||
* @param str Address field
|
||||
* @param options Optional options object
|
||||
* @param options._depth Internal recursion depth counter (do not set manually)
|
||||
* @return An array of address objects
|
||||
*/
|
||||
export default function addressparser(str, options) {
|
||||
function addressparser(str, options) {
|
||||
options = options || {};
|
||||
const depth = options._depth || 0;
|
||||
// Prevent stack overflow from deeply nested groups (DoS protection)
|
||||
@@ -664,3 +648,4 @@ export default function addressparser(str, options) {
|
||||
}
|
||||
return parsedAddresses;
|
||||
}
|
||||
export default addressparser;
|
||||
+2
-1
@@ -20,7 +20,8 @@ export function encode(buffer) {
|
||||
*/
|
||||
export function wrap(str, lineLength) {
|
||||
str = (str || '').toString();
|
||||
lineLength = lineLength || 76;
|
||||
// a negative length would step backwards through the input and never finish
|
||||
lineLength = Math.max(Number(lineLength) || 76, 1);
|
||||
if (str.length <= lineLength) {
|
||||
return str;
|
||||
}
|
||||
|
||||
+13
-1
@@ -30,11 +30,23 @@ declare class DKIM {
|
||||
constructor(options: DKIMOptions);
|
||||
sign(input: Readable | Buffer | string, extraOptions?: DKIMOptions): DKIMSignedStream;
|
||||
}
|
||||
/** The signer options without any key material */
|
||||
export type DKIMOptionalOptions = Omit<DKIMOptions, 'keys' | 'domainName' | 'keySelector' | 'privateKey'>;
|
||||
/** The signer options for a single key given as domainName, keySelector and privateKey */
|
||||
export type DKIMSingleKeyOptions = Omit<DKIMOptions, 'keys'>;
|
||||
/** The signer options for one or more keys given through `keys` */
|
||||
export type DKIMMultipleKeysOptions = DKIMOptionalOptions & {
|
||||
keys: DKIMKey | DKIMKey[];
|
||||
};
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `DKIM.Options` style references keep working
|
||||
*/
|
||||
declare namespace DKIM {
|
||||
type Options = DKIMOptions;
|
||||
type SingleKeyOptions = Omit<DKIMOptions, 'keys'>;
|
||||
type OptionalOptions = DKIMOptionalOptions;
|
||||
type SingleKeyOptions = DKIMSingleKeyOptions;
|
||||
type MultipleKeysOptions = DKIMMultipleKeysOptions;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as DKIM` and `import DKIM = require()` */
|
||||
export type { DKIMOptions as Options, DKIMOptionalOptions as OptionalOptions, DKIMSingleKeyOptions as SingleKeyOptions, DKIMMultipleKeysOptions as MultipleKeysOptions };
|
||||
export default DKIM;
|
||||
+10
-1
@@ -13,7 +13,7 @@ export interface MessageParserHeaderLine {
|
||||
* from the rest of the body. Headers are emitted with the 'headers' event. Message
|
||||
* body is passed on as the resulting stream.
|
||||
*/
|
||||
export default class MessageParser extends Transform {
|
||||
declare class MessageParser extends Transform {
|
||||
lastBytes: Buffer;
|
||||
headersParsed: boolean;
|
||||
headerBytes: number;
|
||||
@@ -37,3 +37,12 @@ export default class MessageParser extends Transform {
|
||||
checkHeaders(data: Buffer): boolean;
|
||||
parseHeaders(): MessageParserHeaderLine[];
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `MessageParser.Header` style references keep working
|
||||
*/
|
||||
declare namespace MessageParser {
|
||||
type Header = MessageParserHeaderLine;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as MessageParser` and `import MessageParser = require()` */
|
||||
export type { MessageParserHeaderLine as Header };
|
||||
export default MessageParser;
|
||||
+2
-1
@@ -4,7 +4,7 @@ import { Transform } from 'node:stream';
|
||||
* from the rest of the body. Headers are emitted with the 'headers' event. Message
|
||||
* body is passed on as the resulting stream.
|
||||
*/
|
||||
export default class MessageParser extends Transform {
|
||||
class MessageParser extends Transform {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.lastBytes = Buffer.alloc(4);
|
||||
@@ -149,3 +149,4 @@ export default class MessageParser extends Transform {
|
||||
}));
|
||||
}
|
||||
}
|
||||
export default MessageParser;
|
||||
+10
-1
@@ -17,7 +17,7 @@ export interface RelaxedBodyOptions {
|
||||
* a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
|
||||
* so a line of any length costs constant memory.
|
||||
*/
|
||||
export default class RelaxedBody extends Transform {
|
||||
declare class RelaxedBody extends Transform {
|
||||
bodyHash: crypto.Hash;
|
||||
/** Bytes of the original body seen so far */
|
||||
byteLength: number;
|
||||
@@ -25,3 +25,12 @@ export default class RelaxedBody extends Transform {
|
||||
constructor(options?: RelaxedBodyOptions);
|
||||
updateHash(chunk: Buffer, final?: boolean): void;
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working
|
||||
*/
|
||||
declare namespace RelaxedBody {
|
||||
type Options = RelaxedBodyOptions;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */
|
||||
export type { RelaxedBodyOptions as Options };
|
||||
export default RelaxedBody;
|
||||
+2
-1
@@ -16,7 +16,7 @@ const EMPTY_LINES = Buffer.alloc(4096, CRLF);
|
||||
* a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive,
|
||||
* so a line of any length costs constant memory.
|
||||
*/
|
||||
export default class RelaxedBody extends Transform {
|
||||
class RelaxedBody extends Transform {
|
||||
constructor(options) {
|
||||
super();
|
||||
options = options || {};
|
||||
@@ -138,3 +138,4 @@ export default class RelaxedBody extends Transform {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
export default RelaxedBody;
|
||||
+3
-2
@@ -64,9 +64,10 @@ export declare const EFETCH = "EFETCH";
|
||||
/**
|
||||
* An Error together with the properties Nodemailer attaches to the errors it
|
||||
* hands to callers. Every property is optional, the set that is present
|
||||
* depends on where the error originated.
|
||||
* depends on where the error originated. Socket level errors keep the errno
|
||||
* and syscall fields Node.js sets on them.
|
||||
*/
|
||||
export interface NodemailerError extends Error {
|
||||
export interface NodemailerError extends NodeJS.ErrnoException {
|
||||
/** Nodemailer error code, see ERROR_CODES */
|
||||
code?: string | undefined;
|
||||
/** SMTP command that was in flight when the server replied with an error */
|
||||
|
||||
+12
-1
@@ -17,13 +17,14 @@ export interface Cookie {
|
||||
secure?: boolean | undefined;
|
||||
httponly?: boolean | undefined;
|
||||
}
|
||||
type CookieEntry = Cookie;
|
||||
/**
|
||||
* Creates a biskviit cookie jar for managing cookie values in memory
|
||||
*
|
||||
* @constructor
|
||||
* @param [options] Optional options object
|
||||
*/
|
||||
export default class Cookies {
|
||||
declare class Cookies {
|
||||
options: CookiesOptions;
|
||||
cookies: Cookie[];
|
||||
constructor(options?: CookiesOptions);
|
||||
@@ -94,3 +95,13 @@ export default class Cookies {
|
||||
*/
|
||||
getPath(pathname?: string | null): string;
|
||||
}
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `Cookies.Cookie` style references keep working
|
||||
*/
|
||||
declare namespace Cookies {
|
||||
type Options = CookiesOptions;
|
||||
type Cookie = CookieEntry;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as Cookies` and `import Cookies = require()` */
|
||||
export type { CookiesOptions as Options };
|
||||
export default Cookies;
|
||||
+2
-1
@@ -8,7 +8,7 @@ const SESSION_TIMEOUT = 1800; // 30 min
|
||||
* @constructor
|
||||
* @param [options] Optional options object
|
||||
*/
|
||||
export default class Cookies {
|
||||
class Cookies {
|
||||
constructor(options) {
|
||||
this.options = options || {};
|
||||
this.cookies = [];
|
||||
@@ -239,3 +239,4 @@ export default class Cookies {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
export default Cookies;
|
||||
+11
@@ -48,4 +48,15 @@ declare function nmfetch(url: string, options?: FetchOptions): FetchResponse;
|
||||
declare namespace nmfetch {
|
||||
var Cookies: typeof import("./cookies.js").default;
|
||||
}
|
||||
type CookiesJar = Cookies;
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working
|
||||
*/
|
||||
declare namespace nmfetch {
|
||||
type Options = FetchOptions;
|
||||
type WritableResponse = FetchResponse;
|
||||
type Cookies = CookiesJar;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */
|
||||
export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies };
|
||||
export default nmfetch;
|
||||
+5
-5
@@ -155,14 +155,14 @@ function nmfetch(url, options) {
|
||||
.join('&'));
|
||||
}
|
||||
catch (E) {
|
||||
if (finished) {
|
||||
return undefined;
|
||||
}
|
||||
// the caller attaches its error listener once nmfetch has returned, so
|
||||
// the error is emitted on the next tick and the stream is handed back
|
||||
// the way every other failure is reported
|
||||
finished = true;
|
||||
E.code = errors.EFETCH;
|
||||
E.sourceUrl = url;
|
||||
fetchRes.emit('error', E);
|
||||
return undefined;
|
||||
setImmediate(() => fetchRes.emit('error', E));
|
||||
return fetchRes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+14
-4
@@ -1,6 +1,6 @@
|
||||
import type { Logger } from '../shared/index.js';
|
||||
import type { MimeNodeEnvelope } from '../mime-node/index.js';
|
||||
import type { default as MailMessage, MailMessageData } from '../mailer/mail-message.js';
|
||||
import type MailMessage from '../mailer/mail-message.js';
|
||||
import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions } from '../mailer/index.js';
|
||||
/**
|
||||
* Options for the JSON transport
|
||||
@@ -12,16 +12,23 @@ export interface JSONTransportOptions extends TransportOptions {
|
||||
skipEncoding?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The value the JSON transport hands to the send callback
|
||||
* The value the JSON transport hands to the send callback. M is the type of the message
|
||||
* field: a JSON string by default, the message object itself when skipEncoding is set
|
||||
*/
|
||||
export interface JSONSentMessageInfo extends SentMessageInfo {
|
||||
export interface JSONSentMessageInfo<M = string> extends SentMessageInfo {
|
||||
/** The envelope the message was generated with */
|
||||
envelope: MimeNodeEnvelope;
|
||||
/** Message-ID value of the message */
|
||||
messageId: string;
|
||||
/** The normalized message as a JSON string, or as the object itself when skipEncoding is set */
|
||||
message: string | MailMessageData;
|
||||
message: M;
|
||||
}
|
||||
/**
|
||||
* The value the JSON transport hands to the send callback when skipEncoding is set: the
|
||||
* message field holds the message object. Typed loosely so that a transporter created with
|
||||
* skipEncoding still fits a variable declared with the plain result type
|
||||
*/
|
||||
export type JSONSentMessageObjectInfo = JSONSentMessageInfo<any>;
|
||||
/**
|
||||
* Generates a Transport object to generate JSON output
|
||||
*
|
||||
@@ -50,5 +57,8 @@ declare namespace JSONTransport {
|
||||
type Options = JSONTransportOptions;
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = JSONSentMessageInfo;
|
||||
type SentMessageObjectInfo = JSONSentMessageObjectInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as JSONTransport` and `import JSONTransport = require()` */
|
||||
export type { JSONTransportOptions as Options, SendMailOptions as MailOptions, JSONSentMessageInfo as SentMessageInfo, JSONSentMessageObjectInfo as SentMessageObjectInfo };
|
||||
export default JSONTransport;
|
||||
+2
@@ -48,6 +48,8 @@ class JSONTransport {
|
||||
}
|
||||
delete data.envelope;
|
||||
delete data.normalizedHeaders;
|
||||
// the message field is the object itself with skipEncoding, the
|
||||
// createTransport overload for that option types the result accordingly
|
||||
return done(null, {
|
||||
envelope,
|
||||
messageId,
|
||||
|
||||
+8
-3
@@ -72,6 +72,11 @@ export type MailComposerListHeaderEntry = string | {
|
||||
export interface MailComposerListHeaders {
|
||||
[key: string]: MailComposerListHeaderEntry | (MailComposerListHeaderEntry | MailComposerListHeaderEntry[])[];
|
||||
}
|
||||
/**
|
||||
* Encoding for the non-ascii header values: quoted-printable ('Q', the default) or base64
|
||||
* ('B'). Only the first letter is read, so the short forms work as well
|
||||
*/
|
||||
export type MailComposerTextEncoding = 'quoted-printable' | 'base64' | 'Q' | 'B';
|
||||
/**
|
||||
* Mail options, the message data MailComposer builds the MIME tree from. The address
|
||||
* fields, subject, messageId, date, inReplyTo and references become headers of the root
|
||||
@@ -114,7 +119,7 @@ export interface MailComposerOptions {
|
||||
/** Content-Transfer-Encoding to force for the text/* nodes that do not set their own */
|
||||
encoding?: string | undefined;
|
||||
/** Header string encoding, 'Q' (the default) or 'B', 'quoted-printable' and 'base64' are accepted as well */
|
||||
textEncoding?: string | undefined;
|
||||
textEncoding?: MailComposerTextEncoding | undefined;
|
||||
/** Pregenerated rfc822 message, used as is instead of building one */
|
||||
raw?: MimeNodeContent | undefined;
|
||||
/** Reject content that points to a URL */
|
||||
@@ -129,8 +134,6 @@ export interface MailComposerOptions {
|
||||
baseBoundary?: string | undefined;
|
||||
/** 'win' for CRLF and 'linux' for LF line breaks in the generated message, kept as is when not set */
|
||||
newline?: string | undefined;
|
||||
/** Keep the Bcc header in the generated message, listed for completeness, the transports set it on the message directly */
|
||||
keepBcc?: boolean | undefined;
|
||||
/** Method to normalize header keys for custom caseing */
|
||||
normalizeHeaderKey?: MimeNodeOptions['normalizeHeaderKey'] | undefined;
|
||||
/** 'high', 'normal' or 'low', sets the priority headers, read by the mailer */
|
||||
@@ -166,4 +169,6 @@ declare class MailComposer {
|
||||
declare namespace MailComposer {
|
||||
type Options = MailComposerOptions;
|
||||
}
|
||||
/** The same alias as a module level export, for `import * as MailComposer` and `import MailComposer = require()` */
|
||||
export type { MailComposerOptions as Options };
|
||||
export default MailComposer;
|
||||
+36
-24
@@ -4,8 +4,8 @@ import DKIM, { type DKIMOptions } from '../dkim/index.js';
|
||||
import MailMessage, { type MailDefaults, type SendMailOptions } from './mail-message.js';
|
||||
import net from 'node:net';
|
||||
import type { ConnectionOptions } from 'node:tls';
|
||||
import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders } from '../mail-composer/index.js';
|
||||
import type { NodemailerError, ResultCallback } from '../errors.js';
|
||||
import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders, MailComposerTextEncoding } from '../mail-composer/index.js';
|
||||
import type { Callback, NodemailerError, ResultCallback } from '../errors.js';
|
||||
import type { ParsedUrl } from '../shared/url.js';
|
||||
import type { MimeNodeAddress, MimeNodeEnvelope, MimeNodeEnvelopeInput, MimeNodeHeaders, MimeNodeOptions } from '../mime-node/index.js';
|
||||
import type { XOAuth2ProvisionCallback } from '../xoauth2/index.js';
|
||||
@@ -15,9 +15,10 @@ export type { default as MailMessage } from './mail-message.js';
|
||||
* The base shape of the object a transport hands back for a sent message. Every bundled
|
||||
* transport sets the envelope and the Message-ID, the rest depends on the transport.
|
||||
*
|
||||
* The index signature keeps a transport specific field readable through this type, and it
|
||||
* is also what a result type has to inherit to stay assignable to it, so the result type
|
||||
* of a transport outside this package has to extend this interface rather than restate it
|
||||
* The index signature keeps a transport specific field readable through this type, the way
|
||||
* the `any` typed result of @types/nodemailer was, and it is also what a result type has
|
||||
* to inherit to stay assignable to it, so the result type of a transport outside this
|
||||
* package has to extend this interface rather than restate it
|
||||
*/
|
||||
export interface SentMessageInfo {
|
||||
/** The envelope the message was sent with */
|
||||
@@ -33,9 +34,9 @@ export interface SentMessageInfo {
|
||||
/** Last response from the server */
|
||||
response?: string | undefined;
|
||||
/** The generated message, for the transports that hand it back instead of sending it */
|
||||
message?: unknown;
|
||||
message?: any;
|
||||
/** Transport specific fields */
|
||||
[key: string]: unknown;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Callback for sendMail, receives the transport result once the transport has taken the
|
||||
@@ -43,9 +44,11 @@ export interface SentMessageInfo {
|
||||
*/
|
||||
export type SendMailCallback<T = SentMessageInfo> = (err: NodemailerError | null, info: T) => void;
|
||||
/**
|
||||
* Callback for verify(), success is true once the transport accepted the configuration
|
||||
* Callback for verify(), success is true once the transport accepted the configuration.
|
||||
* Declared with a required success value, the way @types/nodemailer declared it, the
|
||||
* error path hands over the error alone
|
||||
*/
|
||||
export type VerifyCallback = (err: NodemailerError | null, success?: true) => void;
|
||||
export type VerifyCallback = Callback<true>;
|
||||
/**
|
||||
* Callback a plugin calls once it is done, an error aborts the send
|
||||
*/
|
||||
@@ -60,21 +63,23 @@ export type PluginFunction<T = SentMessageInfo> = (mail: MailMessage<T>, callbac
|
||||
*/
|
||||
export interface GetSocketOptions {
|
||||
host?: string | undefined;
|
||||
port?: number | string | undefined;
|
||||
port?: number | undefined;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* The result of a getSocket handler, the socket to use for the connection
|
||||
* The result of a getSocket handler, the socket to use for the connection. The object is
|
||||
* merged into the connection options, so it may carry any of those as well
|
||||
*/
|
||||
export interface SocketOptions {
|
||||
/** An established socket, the proxied connection */
|
||||
connection?: net.Socket | undefined;
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Receives the socket options from a getSocket handler, or the error that prevented the
|
||||
* connection
|
||||
* Receives the socket options from a getSocket handler, false when a new socket should be
|
||||
* opened, or the error that prevented the connection
|
||||
*/
|
||||
export type GetSocketCallback = (err: NodemailerError | null, socketOptions?: SocketOptions) => void;
|
||||
export type GetSocketCallback = (err: Error | null, socketOptions?: SocketOptions | false) => void;
|
||||
/**
|
||||
* A socket handler. Mail sets one on the transport as getSocket when a proxy is configured,
|
||||
* the SMTP transports call it to get a proxied socket instead of connecting directly
|
||||
@@ -101,9 +106,12 @@ export interface MailMeta {
|
||||
/**
|
||||
* A transport as consumed by Mail: any object with a name, a version and a send method
|
||||
* works, the rest is optional. Mail forwards its close, isIdle and verify calls to the
|
||||
* methods of the same name as they are, so their arguments are up to the transport
|
||||
* methods of the same name as they are, so their arguments are up to the transport.
|
||||
*
|
||||
* D is the options type of the transport, the second type parameter @types/nodemailer
|
||||
* declared on Transport, Transporter and Mail
|
||||
*/
|
||||
export interface Transport<T = SentMessageInfo> {
|
||||
export interface Transport<T = SentMessageInfo, D extends TransportOptions = TransportOptions> {
|
||||
/** Transport name, used for logging */
|
||||
name: string;
|
||||
/** Transport version, used for logging */
|
||||
@@ -119,7 +127,7 @@ export interface Transport<T = SentMessageInfo> {
|
||||
/** Registers an event listener, the transport may emit 'log', 'error', 'idle' and 'clear' */
|
||||
on?(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
/** The Mail object the transport belongs to, set by Mail */
|
||||
mailer?: Mail<T> | undefined;
|
||||
mailer?: Mail<T, D> | undefined;
|
||||
/** Socket handler for a proxied connection, set by Mail when a proxy is configured */
|
||||
getSocket?: GetSocketHandler | undefined;
|
||||
}
|
||||
@@ -150,22 +158,23 @@ export interface TransportOptions {
|
||||
attachDataUrls?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The transporter object createTransport returns, a Mail instance wrapping a transport
|
||||
* The transporter object createTransport returns, a Mail instance wrapping a transport. D
|
||||
* is the options type of the transport, it types the options field of the transporter
|
||||
*/
|
||||
export type Transporter<T = SentMessageInfo> = Mail<T>;
|
||||
export type Transporter<T = SentMessageInfo, D extends TransportOptions = TransportOptions> = Mail<T, D>;
|
||||
/**
|
||||
* Creates an object for exposing the Mail API
|
||||
*
|
||||
* @constructor
|
||||
* @param transporter Transport object instance to pass the mails to
|
||||
*/
|
||||
declare class Mail<out T = SentMessageInfo> extends EventEmitter {
|
||||
options: TransportOptions;
|
||||
declare class Mail<out T = SentMessageInfo, out D extends TransportOptions = TransportOptions> extends EventEmitter {
|
||||
options: D;
|
||||
/** Message defaults given to createTransport, kept public because the DefinitelyTyped typings declared it */
|
||||
_defaults: MailDefaults;
|
||||
meta: Map<string, any>;
|
||||
dkim: DKIM | false;
|
||||
transporter: Transport<T>;
|
||||
transporter: Transport<T, D>;
|
||||
logger: shared.Logger;
|
||||
/** Closes the transport, the pooled SMTP transport closes its connections */
|
||||
close: () => void;
|
||||
@@ -178,7 +187,7 @@ declare class Mail<out T = SentMessageInfo> extends EventEmitter {
|
||||
};
|
||||
/** Socket handler for a proxied connection, set by setupProxy and handed to the transport on the next send */
|
||||
getSocket?: GetSocketHandler | false | undefined;
|
||||
constructor(transporter: Transport<T>, options?: TransportOptions, defaults?: MailDefaults);
|
||||
constructor(transporter: Transport<T, D>, options?: D, defaults?: MailDefaults);
|
||||
use(step: string, plugin: PluginFunction<T>): this;
|
||||
/**
|
||||
* Sends an email using the preselected transport object
|
||||
@@ -213,7 +222,10 @@ declare namespace Mail {
|
||||
type ListHeader = MailComposerListHeaderEntry;
|
||||
type ListHeaders = MailComposerListHeaders;
|
||||
type Envelope = MimeNodeEnvelopeInput;
|
||||
type TextEncoding = NonNullable<SendMailOptions['textEncoding']>;
|
||||
type Connection = SocketOptions;
|
||||
type TextEncoding = MailComposerTextEncoding;
|
||||
type PluginFunction<T = SentMessageInfo> = MailPluginFunction<T>;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as Mail` and `import Mail = require()` */
|
||||
export type { SendMailOptions as Options, MimeNodeAddress as Address, MailComposerAttachment as Attachment, MailComposerAlternative as AttachmentLike, MailComposerAlternative as AmpAttachment, MailComposerIcalEvent as IcalAttachment, MimeNodeHeaders as Headers, MailComposerListHeaderEntry as ListHeader, MailComposerListHeaders as ListHeaders, MimeNodeEnvelopeInput as Envelope, SocketOptions as Connection, MailComposerTextEncoding as TextEncoding };
|
||||
export default Mail;
|
||||
+11
-4
@@ -3,6 +3,7 @@ import type { MailComposerOptions } from '../mail-composer/index.js';
|
||||
import type { DKIMOptions } from '../dkim/index.js';
|
||||
import type { SMTPEnvelopeDsn } from '../smtp-connection/index.js';
|
||||
import type { SMTPTransportAuthOptions } from '../smtp-transport/index.js';
|
||||
import type { SESSendEmailRequest } from '../ses-transport/index.js';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { ResolveContentOptions } from '../shared/index.js';
|
||||
import type Mail from './index.js';
|
||||
@@ -14,6 +15,8 @@ import type { SentMessageInfo } from './index.js';
|
||||
export interface SendMailOptions extends MailComposerOptions {
|
||||
/** DKIM signing options for this message, used instead of the ones of the transporter */
|
||||
dkim?: DKIMOptions | undefined;
|
||||
/** Extra DKIM options for this message, merged over the options of the signer. The SES transport sets skipFields here, the option is not meant for callers */
|
||||
_dkim?: DKIMOptions | undefined;
|
||||
/** Recipients allowed on this message, 0 disables the limit, defaults to 100000 */
|
||||
maxRecipients?: number | undefined;
|
||||
/** SMTP transports: DSN parameters for the envelope, sent when the server supports the DSN extension */
|
||||
@@ -23,9 +26,7 @@ export interface SendMailOptions extends MailComposerOptions {
|
||||
/** SMTP transports: per-message authentication settings, used instead of the transport level auth */
|
||||
auth?: SMTPTransportAuthOptions | undefined;
|
||||
/** SES transport: extra SendEmailCommand parameters merged into the API call */
|
||||
ses?: {
|
||||
[key: string]: unknown;
|
||||
} | undefined;
|
||||
ses?: SESSendEmailRequest | undefined;
|
||||
}
|
||||
/**
|
||||
* Default message fields, the third argument of createTransport. Applied to every message
|
||||
@@ -71,7 +72,13 @@ export interface MailMessageListHeader {
|
||||
export default class MailMessage<T = SentMessageInfo> {
|
||||
mailer: Mail<T>;
|
||||
data: MailMessageData;
|
||||
message: MimeNode | null;
|
||||
/**
|
||||
* The compiled MIME tree. Set once the compile step is done, so it is null while the
|
||||
* 'compile' plugins run and set by the time the 'stream' plugins and the transport see
|
||||
* the message. Declared as always set, the way @types/nodemailer declared it, since the
|
||||
* plugins that read it are the ones that run after it is set
|
||||
*/
|
||||
message: MimeNode;
|
||||
constructor(mailer: Mail<T>, data?: SendMailOptions);
|
||||
resolveContent(data: {
|
||||
[key: string]: any;
|
||||
|
||||
+5
-2
@@ -2,8 +2,8 @@
|
||||
* A header value split into the value token and its parameters, the result of parseHeaderValue
|
||||
*/
|
||||
export interface ParsedHeaderValue {
|
||||
/** The value ahead of the parameters, for example the content type */
|
||||
value: string | false;
|
||||
/** The value ahead of the parameters, for example the content type, an empty string when there is none */
|
||||
value: string;
|
||||
/** Parameter values keyed by lowercase parameter name */
|
||||
params: Record<string, string>;
|
||||
}
|
||||
@@ -25,6 +25,9 @@ export interface EncodedHeaderParam {
|
||||
/** Parameter value of this part */
|
||||
value: string;
|
||||
}
|
||||
/** The names @types/nodemailer used for the two types above */
|
||||
export type HeaderValue = StructuredHeaderValue;
|
||||
export type ParsedHeaderParam = EncodedHeaderParam;
|
||||
/**
|
||||
* Checks if a value is plaintext string (uses only printable 7bit chars)
|
||||
*
|
||||
|
||||
+1
-1
@@ -353,7 +353,7 @@ export function buildHeaderParam(key, data, maxLength) {
|
||||
*/
|
||||
export function parseHeaderValue(str) {
|
||||
const response = {
|
||||
value: false,
|
||||
value: '',
|
||||
params: {}
|
||||
};
|
||||
// Parameter names come from a caller supplied contentType/contentDisposition. A
|
||||
|
||||
+5
-2
@@ -108,10 +108,11 @@ export interface MimeNodeEnvelope {
|
||||
}
|
||||
/**
|
||||
* Envelope as accepted by setEnvelope. Recipients are collected from to, cc and bcc, any
|
||||
* other field is copied to the envelope as is
|
||||
* other field is copied to the envelope as is. A `from` of false is the null sender of a
|
||||
* bounce message, it is sent as MAIL FROM:<>
|
||||
*/
|
||||
export interface MimeNodeEnvelopeInput {
|
||||
from?: MimeNodeAddressInput | undefined;
|
||||
from?: MimeNodeAddressInput | false | undefined;
|
||||
to?: MimeNodeAddressInput | undefined;
|
||||
cc?: MimeNodeAddressInput | undefined;
|
||||
bcc?: MimeNodeAddressInput | undefined;
|
||||
@@ -327,4 +328,6 @@ declare namespace MimeNode {
|
||||
type Addresses = MimeNodeAddresses;
|
||||
type Envelope = MimeNodeEnvelope;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */
|
||||
export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope };
|
||||
export default MimeNode;
|
||||
+25
-14
@@ -1,10 +1,16 @@
|
||||
import Mail from './mailer/index.js';
|
||||
import type { MailDefaults, SentMessageInfo, Transport, TransportOptions } from './mailer/index.js';
|
||||
import SMTPPool from './smtp-pool/index.js';
|
||||
import type { SMTPPoolOptions, SMTPPoolSentMessageInfo } from './smtp-pool/index.js';
|
||||
import SMTPTransport from './smtp-transport/index.js';
|
||||
import type { SMTPTransportOptions, SMTPSentMessageInfo } from './smtp-transport/index.js';
|
||||
import SendmailTransport from './sendmail-transport/index.js';
|
||||
import type { SendmailTransportOptions, SendmailSentMessageInfo } from './sendmail-transport/index.js';
|
||||
import StreamTransport from './stream-transport/index.js';
|
||||
import type { StreamTransportOptions, StreamSentMessageInfo } from './stream-transport/index.js';
|
||||
import type { JSONTransportOptions, JSONSentMessageInfo } from './json-transport/index.js';
|
||||
import JSONTransport from './json-transport/index.js';
|
||||
import type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo } from './json-transport/index.js';
|
||||
import SESTransport from './ses-transport/index.js';
|
||||
import type { SESTransportOptions, SESSentMessageInfo } from './ses-transport/index.js';
|
||||
/**
|
||||
* Connection details of a service endpoint of an Ethereal test account
|
||||
@@ -43,24 +49,29 @@ export type TransportConfig = SMTPTransportOptions | SMTPPoolOptions | SendmailT
|
||||
* @param defaults Default message fields that are merged into every message
|
||||
* @returns Mail instance wrapping the transport
|
||||
*/
|
||||
export declare function createTransport(transporter: SMTPPoolOptions & {
|
||||
export declare function createTransport(transporter: SMTPPool | (SMTPPoolOptions & {
|
||||
pool: true;
|
||||
}, defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo>;
|
||||
export declare function createTransport(transporter: SendmailTransportOptions & {
|
||||
}), defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions>;
|
||||
export declare function createTransport(transporter: SendmailTransport | (SendmailTransportOptions & {
|
||||
sendmail: true | string;
|
||||
}, defaults?: MailDefaults): Mail<SendmailSentMessageInfo>;
|
||||
export declare function createTransport(transporter: StreamTransportOptions & {
|
||||
}), defaults?: MailDefaults): Mail<SendmailSentMessageInfo, SendmailTransportOptions>;
|
||||
export declare function createTransport(transporter: StreamTransport | (StreamTransportOptions & {
|
||||
streamTransport: true;
|
||||
}, defaults?: MailDefaults): Mail<StreamSentMessageInfo>;
|
||||
}), defaults?: MailDefaults): Mail<StreamSentMessageInfo, StreamTransportOptions>;
|
||||
export declare function createTransport(transporter: JSONTransportOptions & {
|
||||
jsonTransport: true;
|
||||
}, defaults?: MailDefaults): Mail<JSONSentMessageInfo>;
|
||||
export declare function createTransport(transporter: SESTransportOptions & {
|
||||
skipEncoding: true;
|
||||
}, defaults?: MailDefaults): Mail<JSONSentMessageObjectInfo, JSONTransportOptions>;
|
||||
export declare function createTransport(transporter: JSONTransport | (JSONTransportOptions & {
|
||||
jsonTransport: true;
|
||||
}), defaults?: MailDefaults): Mail<JSONSentMessageInfo, JSONTransportOptions>;
|
||||
export declare function createTransport(transporter: SESTransport | (SESTransportOptions & {
|
||||
SES: object;
|
||||
}, defaults?: MailDefaults): Mail<SESSentMessageInfo>;
|
||||
export declare function createTransport<T = SentMessageInfo>(transporter: Transport<T>, defaults?: MailDefaults): Mail<T>;
|
||||
export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo>;
|
||||
export declare function createTransport(transporter?: TransportConfig | Transport<any> | string, defaults?: MailDefaults): Mail<any>;
|
||||
}), defaults?: MailDefaults): Mail<SESSentMessageInfo, SESTransportOptions>;
|
||||
export declare function createTransport(transporter: SMTPTransport, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
|
||||
export declare function createTransport<T = SentMessageInfo, D extends TransportOptions = TransportOptions>(transporter: Transport<T, D>, defaults?: MailDefaults): Mail<T, D>;
|
||||
export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
|
||||
export declare function createTransport(transporter?: TransportConfig | Transport<any, any> | string, defaults?: MailDefaults): Mail<any, any>;
|
||||
/**
|
||||
* Creates a test account from the Ethereal service (https://ethereal.email)
|
||||
*
|
||||
@@ -98,5 +109,5 @@ export type { SMTPTransportOptions, SMTPSentMessageInfo };
|
||||
export type { SMTPPoolOptions, SMTPPoolSentMessageInfo };
|
||||
export type { SendmailTransportOptions, SendmailSentMessageInfo };
|
||||
export type { StreamTransportOptions, StreamSentMessageInfo };
|
||||
export type { JSONTransportOptions, JSONSentMessageInfo };
|
||||
export type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo };
|
||||
export type { SESTransportOptions, SESSentMessageInfo };
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
export declare const name = "nodemailer";
|
||||
export declare const version = "10.0.10";
|
||||
export declare const version = "10.0.11";
|
||||
export declare const homepage = "https://nodemailer.com/";
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Generated by scripts/build.js from package.json. Do not edit by hand.
|
||||
export const name = 'nodemailer';
|
||||
export const version = '10.0.10';
|
||||
export const version = '10.0.11';
|
||||
export const homepage = 'https://nodemailer.com/';
|
||||
+2
@@ -15,6 +15,8 @@ export interface QPEncoderOptions {
|
||||
/** Maximum length for lines, set to false to disable wrapping */
|
||||
lineLength?: number | false | undefined;
|
||||
}
|
||||
/** The name @types/nodemailer used for QPEncoderOptions */
|
||||
export type EncoderOptions = QPEncoderOptions;
|
||||
/**
|
||||
* Creates a transform stream for encoding data to Quoted-Printable encoding
|
||||
*
|
||||
|
||||
+10
-1
@@ -5,6 +5,8 @@ import { Transform } from 'node:stream';
|
||||
* @param buffer Buffer to convert
|
||||
* @returns Quoted-Printable encoded string
|
||||
*/
|
||||
// the shortest line wrap() can make progress with: a complete =XX sequence and the soft break
|
||||
const MIN_LINE_LENGTH = 4;
|
||||
// usable characters that do not need encoding
|
||||
// https://tools.ietf.org/html/rfc2045#section-6.7
|
||||
const QP_RANGES = [
|
||||
@@ -41,7 +43,9 @@ export function encode(buffer) {
|
||||
*/
|
||||
export function wrap(str, lineLength) {
|
||||
str = (str || '').toString();
|
||||
lineLength = lineLength || 76;
|
||||
// a line has to hold a complete =XX sequence plus the soft break, shorter lengths
|
||||
// (or a negative one) would loop without consuming input
|
||||
lineLength = Math.max(Number(lineLength) || 76, MIN_LINE_LENGTH);
|
||||
if (str.length <= lineLength) {
|
||||
return str;
|
||||
}
|
||||
@@ -95,6 +99,11 @@ export function wrap(str, lineLength) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!line.length) {
|
||||
// the trimming above emptied the line, which only happens for an incomplete
|
||||
// escape at the very end of the input. Take it as is rather than loop on it
|
||||
line = str.substr(pos, lineLength);
|
||||
}
|
||||
if (pos + line.length < len && line.substr(-1) !== '\n') {
|
||||
if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) {
|
||||
line = line.substr(0, line.length - 3);
|
||||
|
||||
+2
@@ -64,4 +64,6 @@ declare namespace SendmailTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SendmailSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SendmailTransport` and `import SendmailTransport = require()` */
|
||||
export type { SendmailTransportOptions as Options, SendMailOptions as MailOptions, SendmailSentMessageInfo as SentMessageInfo };
|
||||
export default SendmailTransport;
|
||||
+33
-1
@@ -21,6 +21,32 @@ export interface SESTransportOptions extends TransportOptions {
|
||||
SendEmailCommand: new (input: any) => unknown;
|
||||
};
|
||||
}
|
||||
/** The SESv2Client shape the transport needs */
|
||||
export type SESTransportClient = SESTransportOptions['SES']['sesClient'];
|
||||
/** The SendEmailCommand constructor shape the transport needs */
|
||||
export type SESTransportSendEmailCommand = SESTransportOptions['SES']['SendEmailCommand'];
|
||||
/**
|
||||
* SendEmailCommand parameters, the shape of the `ses` message option that is merged into
|
||||
* the API call. Any further SendEmailCommandInput field is accepted as well
|
||||
*/
|
||||
export interface SESSendEmailRequest {
|
||||
FromEmailAddress?: string | undefined;
|
||||
Destination?: {
|
||||
ToAddresses?: string[] | undefined;
|
||||
CcAddresses?: string[] | undefined;
|
||||
BccAddresses?: string[] | undefined;
|
||||
} | undefined;
|
||||
ReplyToAddresses?: string[] | undefined;
|
||||
Content?: unknown;
|
||||
EmailTags?: Array<{
|
||||
Name?: string | undefined;
|
||||
Value?: string | undefined;
|
||||
}> | undefined;
|
||||
ConfigurationSetName?: string | undefined;
|
||||
ListManagementOptions?: unknown;
|
||||
FeedbackForwardingEmailAddress?: string | undefined;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
/**
|
||||
* The value the SES transport hands to the send callback
|
||||
*/
|
||||
@@ -47,7 +73,7 @@ declare class SESTransport extends EventEmitter {
|
||||
name: string;
|
||||
version: string;
|
||||
logger: Logger;
|
||||
constructor(options?: SESTransportOptions);
|
||||
constructor(options: SESTransportOptions);
|
||||
getRegion(cb: (err: Error | null, region?: string | false) => void): void;
|
||||
/**
|
||||
* Compiles a mailcomposer message and forwards it to SES
|
||||
@@ -71,5 +97,11 @@ declare namespace SESTransport {
|
||||
type Options = SESTransportOptions;
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SESSentMessageInfo;
|
||||
type SESv2ClientLike = SESTransportClient;
|
||||
type SendEmailCommandConstructorLike = SESTransportSendEmailCommand;
|
||||
type SendEmailRequestLike = SESSendEmailRequest;
|
||||
type MailSesOptions = SESSendEmailRequest;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SESTransport` and `import SESTransport = require()` */
|
||||
export type { SESTransportOptions as Options, SendMailOptions as MailOptions, SESSentMessageInfo as SentMessageInfo, SESTransportClient as SESv2ClientLike, SESTransportSendEmailCommand as SendEmailCommandConstructorLike, SESSendEmailRequest as SendEmailRequestLike, SESSendEmailRequest as MailSesOptions };
|
||||
export default SESTransport;
|
||||
+18
-6
@@ -34,6 +34,8 @@ export interface ResolvedHostname {
|
||||
/** The resolver error when a cached value was used because of it */
|
||||
error?: Error | undefined;
|
||||
}
|
||||
/** The name @types/nodemailer used for ResolvedHostname */
|
||||
export type ResolveHostnameValue = ResolvedHostname;
|
||||
/**
|
||||
* Resolved addresses as stored in the DNS cache
|
||||
*/
|
||||
@@ -83,6 +85,8 @@ export interface LogEntry {
|
||||
[key: string]: any;
|
||||
}
|
||||
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
/** The name @types/nodemailer used for LogLevel */
|
||||
export type LoggerLevel = LogLevel;
|
||||
/**
|
||||
* A logger supplied by the caller, bunyan style. Any object works, a level it does not
|
||||
* implement is routed to one it does, see _logFunc
|
||||
@@ -104,16 +108,24 @@ export interface GetLoggerOptions {
|
||||
/** A bunyan compatible logger, true for the default console logger, false or unset for no logging */
|
||||
logger?: ExternalLogger | boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* A bunyan style log method: a data object followed by a printf style message, or the
|
||||
* message alone
|
||||
*/
|
||||
export interface LogMethod {
|
||||
(data: LogEntry | undefined, message?: string, ...args: any[]): void;
|
||||
(message?: string, ...args: any[]): void;
|
||||
}
|
||||
/**
|
||||
* The bunyan compatible logger interface returned by getLogger
|
||||
*/
|
||||
export interface Logger {
|
||||
trace(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
debug(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
info(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
warn(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
error(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
fatal(data?: LogEntry, message?: string, ...args: any[]): void;
|
||||
trace: LogMethod;
|
||||
debug: LogMethod;
|
||||
info: LogMethod;
|
||||
warn: LogMethod;
|
||||
error: LogMethod;
|
||||
fatal: LogMethod;
|
||||
}
|
||||
/**
|
||||
* A parsed data URI
|
||||
|
||||
+4
-2
@@ -333,8 +333,10 @@ export const getLogger = (options, defaults) => {
|
||||
}
|
||||
const logger = options.logger === true ? createDefaultLogger(levels) : options.logger;
|
||||
levels.forEach(level => {
|
||||
response[level] = (data, message, ...args) => {
|
||||
_logFunc(logger, level, defaults, data, message, ...args);
|
||||
response[level] = (...args) => {
|
||||
// the bunyan forms: a data object first, or the message alone
|
||||
const data = typeof args[0] === 'string' ? undefined : args.shift();
|
||||
_logFunc(logger, level, defaults, data, ...args);
|
||||
};
|
||||
});
|
||||
return response;
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
* Minimal HTTP/S proxy client
|
||||
*/
|
||||
import net from 'node:net';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback } from '../errors.js';
|
||||
/**
|
||||
* TLS options for connecting to an HTTPS proxy
|
||||
*/
|
||||
@@ -13,7 +13,7 @@ export interface HttpProxyClientOptions {
|
||||
/**
|
||||
* Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it
|
||||
*/
|
||||
export type HttpProxyClientCallback = (err: NodemailerError | null, socket?: net.Socket) => void;
|
||||
export type HttpProxyClientCallback = Callback<net.Socket>;
|
||||
/**
|
||||
* Establishes proxied connection to destinationPort
|
||||
*
|
||||
|
||||
+6
-4
@@ -14,6 +14,8 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
tlsOptions = {};
|
||||
}
|
||||
tlsOptions = tlsOptions || {};
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
// Reject CRLF in the destination before it reaches the CONNECT request line
|
||||
// and Host header. A tainted host/port could otherwise inject additional
|
||||
// request headers into the proxy connection (HTTP request splitting).
|
||||
@@ -21,7 +23,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
if (!destinationPort || /[\r\n]/.test(destinationHost)) {
|
||||
const err = new Error('Invalid proxy destination');
|
||||
err.code = errors.EPROXY;
|
||||
setImmediate(() => callback(err));
|
||||
setImmediate(() => done(err));
|
||||
return;
|
||||
}
|
||||
const proxy = urllib.parse(proxyUrl);
|
||||
@@ -55,7 +57,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
catch (_E) {
|
||||
// ignore
|
||||
}
|
||||
callback(err);
|
||||
done(err);
|
||||
};
|
||||
const timeoutErr = () => {
|
||||
const err = new Error('Proxy socket timed out');
|
||||
@@ -114,12 +116,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions,
|
||||
}
|
||||
const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || ''));
|
||||
err.code = errors.EPROXY;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
socket.removeListener('error', tempSocketErr);
|
||||
socket.removeListener('timeout', timeoutErr);
|
||||
socket.setTimeout(0);
|
||||
return callback(null, socket);
|
||||
return done(null, socket);
|
||||
}
|
||||
if (headers.length > MAX_RESPONSE_HEADER_BYTES) {
|
||||
socket.removeListener('data', onSocketData);
|
||||
|
||||
+57
-22
@@ -3,8 +3,9 @@ import net from 'node:net';
|
||||
import tls from 'node:tls';
|
||||
import { type Readable } from 'node:stream';
|
||||
import * as shared from '../shared/index.js';
|
||||
import type { NodemailerError } from '../errors.js';
|
||||
import type { Callback, NodemailerError } from '../errors.js';
|
||||
import type XOAuth2 from '../xoauth2/index.js';
|
||||
import type { XOAuth2Options } from '../xoauth2/index.js';
|
||||
/**
|
||||
* Custom authentication handlers keyed by (case insensitive) SASL method name
|
||||
*/
|
||||
@@ -117,12 +118,23 @@ export interface SMTPConnectionCustomAuthResponse {
|
||||
* Callback for a command sent by a custom authentication handler
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthCommandCallback = (err: Error | null, data: SMTPConnectionCustomAuthResponse) => void;
|
||||
/**
|
||||
* The auth object as a custom authentication handler sees it: the object handed to login()
|
||||
* with the credentials filled in from its user and pass values
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthData extends SMTPConnectionAuth {
|
||||
/** The user and pass values of the auth object, the way @types/nodemailer declared them */
|
||||
credentials: SMTPConnectionCredentials & {
|
||||
user: string;
|
||||
pass: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* The object a custom authentication handler is run with
|
||||
*/
|
||||
export interface SMTPConnectionCustomAuthContext {
|
||||
/** The auth object handed to login() */
|
||||
auth: SMTPConnectionAuth;
|
||||
/** The auth object handed to login(), with the credentials filled in */
|
||||
auth: SMTPConnectionCustomAuthData;
|
||||
/** Selected authentication method name */
|
||||
method: string;
|
||||
/** SMTP extensions the server advertised */
|
||||
@@ -131,17 +143,20 @@ export interface SMTPConnectionCustomAuthContext {
|
||||
authMethods: string[];
|
||||
/** Maximum message size the server accepts, false when not advertised */
|
||||
maxAllowedSize: number | false;
|
||||
/** Sends a command to the server. Returns a promise when no callback is given */
|
||||
sendCommand(cmd: string, done?: SMTPConnectionCustomAuthCommandCallback): Promise<SMTPConnectionCustomAuthResponse> | undefined;
|
||||
/** Sends a command to the server and resolves with the parsed reply */
|
||||
sendCommand(cmd: string): Promise<SMTPConnectionCustomAuthResponse>;
|
||||
/** Sends a command to the server and hands the parsed reply to the callback */
|
||||
sendCommand(cmd: string, done: SMTPConnectionCustomAuthCommandCallback): void;
|
||||
/** Marks the user as authenticated */
|
||||
resolve(): void;
|
||||
/** Fails the authentication with an error */
|
||||
reject(err: Error | string): void;
|
||||
}
|
||||
/**
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a promise
|
||||
* A custom authentication handler. Calls resolve() or reject() on the context, or returns a
|
||||
* promise that settles the authentication. Any other return value is ignored
|
||||
*/
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => void | Promise<unknown>;
|
||||
export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => unknown;
|
||||
/**
|
||||
* An envelope address, either a plain string or an object with an address property
|
||||
*/
|
||||
@@ -168,12 +183,16 @@ export interface SMTPEnvelopeDsn {
|
||||
/** Alias of recipient, in the 'rfc822;address' form */
|
||||
orcpt?: string | null | undefined;
|
||||
}
|
||||
/**
|
||||
* A single DSN notify value
|
||||
*/
|
||||
export type SMTPEnvelopeDsnNotify = 'NEVER' | 'SUCCESS' | 'FAILURE' | 'DELAY';
|
||||
/**
|
||||
* Envelope object accepted by send()
|
||||
*/
|
||||
export interface SMTPEnvelope {
|
||||
/** Sender address */
|
||||
from?: string | SMTPEnvelopeAddress | undefined;
|
||||
/** Sender address, false for the null sender of a bounce message (MAIL FROM:<>) */
|
||||
from?: string | SMTPEnvelopeAddress | false | undefined;
|
||||
/** Recipient address or addresses */
|
||||
to?: string | SMTPEnvelopeAddress | Array<string | SMTPEnvelopeAddress> | undefined;
|
||||
/** Message size in bytes, sent as the SIZE parameter when the server supports it */
|
||||
@@ -202,9 +221,9 @@ export interface SMTPConnectionEnvelope extends SMTPEnvelope {
|
||||
accepted: string[];
|
||||
}
|
||||
/**
|
||||
* Result of a sent message
|
||||
* The recipient bookkeeping of a sent message, known once the envelope is accepted
|
||||
*/
|
||||
export interface SMTPConnectionSendInfo {
|
||||
export interface SMTPConnectionEnvelopeInfo {
|
||||
/** Recipients the server accepted */
|
||||
accepted: string[];
|
||||
/** Recipients the server rejected */
|
||||
@@ -213,19 +232,25 @@ export interface SMTPConnectionSendInfo {
|
||||
ehlo?: string[] | undefined;
|
||||
/** Errors for the rejected recipients */
|
||||
rejectedErrors?: NodemailerError[] | undefined;
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime?: number | undefined;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime?: number | undefined;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize?: number | undefined;
|
||||
/** Final server response for the message */
|
||||
response?: string | undefined;
|
||||
}
|
||||
/**
|
||||
* Callback for send()
|
||||
* Result of a sent message
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = (err: NodemailerError | null, info?: SMTPConnectionSendInfo) => void;
|
||||
export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo {
|
||||
/** Time in ms spent on the envelope commands */
|
||||
envelopeTime: number;
|
||||
/** Time in ms spent on streaming the message */
|
||||
messageTime: number;
|
||||
/** Size of the encoded message in bytes */
|
||||
messageSize: number;
|
||||
/** Final server response for the message */
|
||||
response: string;
|
||||
}
|
||||
/**
|
||||
* Callback for send(), receives the result once the server accepted the message. The error
|
||||
* path hands over the error alone
|
||||
*/
|
||||
export type SMTPConnectionSendCallback = Callback<SMTPConnectionSendInfo>;
|
||||
/**
|
||||
* Callback for login() and reset(), the result is true on success
|
||||
*/
|
||||
@@ -285,7 +310,7 @@ export type SMTPConnectionResponseAction = (str: string) => void;
|
||||
*/
|
||||
declare class SMTPConnection extends EventEmitter {
|
||||
id: string;
|
||||
stage: string;
|
||||
stage: 'init' | 'connected';
|
||||
options: SMTPConnectionOptions;
|
||||
secureConnection: boolean;
|
||||
alreadySecured: boolean;
|
||||
@@ -370,12 +395,22 @@ declare class SMTPConnection extends EventEmitter {
|
||||
declare namespace SMTPConnection {
|
||||
type Options = SMTPConnectionOptions;
|
||||
type AuthenticationType = SMTPConnectionAuth;
|
||||
type AuthenticationTypeLogin = SMTPConnectionAuth;
|
||||
type AuthenticationTypeOAuth2 = SMTPConnectionAuth;
|
||||
type AuthenticationTypeCustom = SMTPConnectionAuth;
|
||||
type AuthenticationCredentials = SMTPConnectionAuth;
|
||||
type AuthenticationOAuth2 = SMTPConnectionAuth;
|
||||
type Credentials = SMTPConnectionCredentials;
|
||||
type OAuth2 = XOAuth2Options;
|
||||
type Envelope = SMTPEnvelope;
|
||||
type DSNOptions = SMTPEnvelopeDsn;
|
||||
type DSNOption = SMTPEnvelopeDsnNotify;
|
||||
type SentMessageInfo = SMTPConnectionSendInfo;
|
||||
type SMTPError = NodemailerError;
|
||||
type CustomAuthenticationContext = SMTPConnectionCustomAuthContext;
|
||||
type CustomAuthenticationResponse = SMTPConnectionCustomAuthResponse;
|
||||
type CustomAuthenticationHandlers = SMTPConnectionCustomAuthHandlers;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPConnection` and `import SMTPConnection = require()` */
|
||||
export type { SMTPConnectionOptions as Options, SMTPConnectionAuth as AuthenticationType, SMTPConnectionAuth as AuthenticationTypeLogin, SMTPConnectionAuth as AuthenticationTypeOAuth2, SMTPConnectionAuth as AuthenticationTypeCustom, SMTPConnectionAuth as AuthenticationCredentials, SMTPConnectionAuth as AuthenticationOAuth2, SMTPConnectionCredentials as Credentials, XOAuth2Options as OAuth2, SMTPEnvelope as Envelope, SMTPEnvelopeDsn as DSNOptions, SMTPEnvelopeDsnNotify as DSNOption, SMTPConnectionSendInfo as SentMessageInfo, NodemailerError as SMTPError, SMTPConnectionCustomAuthContext as CustomAuthenticationContext, SMTPConnectionCustomAuthResponse as CustomAuthenticationResponse, SMTPConnectionCustomAuthHandlers as CustomAuthenticationHandlers };
|
||||
export default SMTPConnection;
|
||||
+68
-55
@@ -414,14 +414,21 @@ class SMTPConnection extends EventEmitter {
|
||||
this._auth = authData || {};
|
||||
// Select SASL authentication method
|
||||
this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
|
||||
// XOAUTH2 needs a token generator or a custom handler, without either the method
|
||||
// can not be run even when it is the only one the server advertised
|
||||
const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2');
|
||||
if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) {
|
||||
this._authMethod = 'XOAUTH2';
|
||||
}
|
||||
else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) {
|
||||
// use first supported
|
||||
this._authMethod = (this._supportedAuth[0] || 'PLAIN').toUpperCase().trim();
|
||||
// use the first supported method that can be run
|
||||
const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2);
|
||||
this._authMethod = (supported || 'PLAIN').toUpperCase().trim();
|
||||
}
|
||||
if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
// a token login needs no credentials, every other method and every custom handler
|
||||
// gets them filled in from the user and pass values
|
||||
if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) &&
|
||||
(!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) {
|
||||
this._auth.credentials = {
|
||||
user: this._auth.user,
|
||||
@@ -458,42 +465,45 @@ class SMTPConnection extends EventEmitter {
|
||||
returned = true;
|
||||
callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod));
|
||||
};
|
||||
// one implementation serves both sendCommand overloads, the promise is returned
|
||||
// exactly when no callback was given
|
||||
const sendCommand = (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
};
|
||||
const handlerResponse = handler({
|
||||
auth: this._auth,
|
||||
method: this._authMethod,
|
||||
extensions: [].concat(this._supportedExtensions),
|
||||
authMethods: [].concat(this._supportedAuth),
|
||||
maxAllowedSize: this._maxAllowedSize || false,
|
||||
sendCommand: (cmd, done) => {
|
||||
let promise;
|
||||
if (!done) {
|
||||
promise = new Promise((resolve, reject) => {
|
||||
done = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
this._responseActions.push(str => {
|
||||
lastResponse = str;
|
||||
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
||||
let data = {
|
||||
command: cmd,
|
||||
response: str
|
||||
};
|
||||
if (codes) {
|
||||
data.status = Number(codes[1]) || 0;
|
||||
if (codes[2]) {
|
||||
data.code = codes[2];
|
||||
}
|
||||
data.text = str.substr(codes[0].length);
|
||||
}
|
||||
else {
|
||||
data.text = str;
|
||||
data.status = 0; // just in case we need to perform numeric comparisons
|
||||
}
|
||||
done(null, data);
|
||||
});
|
||||
setImmediate(() => this._sendCommand(cmd));
|
||||
return promise;
|
||||
},
|
||||
sendCommand: sendCommand,
|
||||
resolve,
|
||||
reject
|
||||
});
|
||||
@@ -550,29 +560,30 @@ class SMTPConnection extends EventEmitter {
|
||||
* @param callback Callback to return once sending is completed
|
||||
*/
|
||||
send(envelope, message, done) {
|
||||
if (!message) {
|
||||
return done(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return done(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
done(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
// ensure that callback is only called once
|
||||
// ensure that the callback is only called once. The public callback type has a
|
||||
// required result, the error paths hand over the error alone
|
||||
let returned = false;
|
||||
const callback = function (...args) {
|
||||
const callback = (err, info) => {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
done(...args);
|
||||
done(err, info);
|
||||
};
|
||||
if (!message) {
|
||||
return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
||||
}
|
||||
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
||||
if (isDestroyedMessage) {
|
||||
return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
||||
}
|
||||
// reject larger messages than allowed
|
||||
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
||||
setImmediate(() => {
|
||||
callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (typeof message.on === 'function') {
|
||||
message.on('error', err => callback(this._formatError(err, 'ESTREAM', false, 'API')));
|
||||
}
|
||||
@@ -595,11 +606,13 @@ class SMTPConnection extends EventEmitter {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
info.envelopeTime = envelopeTime - startTime;
|
||||
info.messageTime = Date.now() - envelopeTime;
|
||||
info.messageSize = stream.outByteCount;
|
||||
info.response = str;
|
||||
return callback(null, info);
|
||||
// the envelope info becomes the send result once the timings are on it
|
||||
const result = info;
|
||||
result.envelopeTime = envelopeTime - startTime;
|
||||
result.messageTime = Date.now() - envelopeTime;
|
||||
result.messageSize = stream.outByteCount;
|
||||
result.response = str;
|
||||
return callback(null, result);
|
||||
});
|
||||
if (typeof message.pipe === 'function') {
|
||||
message.pipe(stream);
|
||||
|
||||
+4
-2
@@ -80,7 +80,7 @@ declare class SMTPPool extends EventEmitter {
|
||||
/**
|
||||
* The Mail instance using this transport, assigned by Mail
|
||||
*/
|
||||
mailer?: Mail<SMTPPoolSentMessageInfo> | undefined;
|
||||
mailer?: Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions> | undefined;
|
||||
constructor(options?: SMTPPoolOptions | string);
|
||||
/**
|
||||
* Placeholder function for creating proxy sockets. This method immediatelly returns
|
||||
@@ -96,7 +96,7 @@ declare class SMTPPool extends EventEmitter {
|
||||
* @param mail Mail object
|
||||
* @param callback Callback function
|
||||
*/
|
||||
send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean;
|
||||
send(mail: MailMessage<SMTPPoolSentMessageInfo>, callback: SMTPPoolSendCallback): boolean;
|
||||
/**
|
||||
* Closes all connections in the pool. If there is a message being sent, the connection
|
||||
* is closed later
|
||||
@@ -122,4 +122,6 @@ declare namespace SMTPPool {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SMTPPoolSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPPool` and `import SMTPPool = require()` */
|
||||
export type { SMTPPoolOptions as Options, SendMailOptions as MailOptions, SMTPPoolSentMessageInfo as SentMessageInfo };
|
||||
export default SMTPPool;
|
||||
+8
-6
@@ -424,10 +424,12 @@ class SMTPPool extends EventEmitter {
|
||||
callback = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
const auth = new PoolResource(this).auth;
|
||||
this.getSocket(this.options, (err, socketOptions) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
let options = this.options;
|
||||
if (socketOptions && socketOptions.connection) {
|
||||
@@ -449,14 +451,14 @@ class SMTPPool extends EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
connection.once('end', () => {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
return callback(new Error('Connection closed'));
|
||||
return done(new Error('Connection closed'));
|
||||
});
|
||||
const finalize = () => {
|
||||
if (returned) {
|
||||
@@ -464,7 +466,7 @@ class SMTPPool extends EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
connection.quit();
|
||||
return callback(null, true);
|
||||
return done(null, true);
|
||||
};
|
||||
connection.connect(() => {
|
||||
if (returned) {
|
||||
@@ -478,7 +480,7 @@ class SMTPPool extends EventEmitter {
|
||||
if (err) {
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
finalize();
|
||||
});
|
||||
@@ -488,7 +490,7 @@ class SMTPPool extends EventEmitter {
|
||||
err.code = errors.ENOAUTH;
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
else {
|
||||
finalize();
|
||||
|
||||
+1
-3
@@ -100,9 +100,7 @@ export default class PoolResource extends EventEmitter {
|
||||
}
|
||||
// still have not returned, this means we have an unexpected connection close
|
||||
const err = new Error('Unexpected socket close');
|
||||
if (this.connection &&
|
||||
this.connection._socket &&
|
||||
this.connection._socket.upgrading) {
|
||||
if (this.connection && this.connection.upgrading) {
|
||||
// starttls connection errors
|
||||
err.code = errors.ETLS;
|
||||
}
|
||||
|
||||
+13
-5
@@ -4,7 +4,7 @@ import * as shared from '../shared/index.js';
|
||||
import { type XOAuth2Options } from '../xoauth2/index.js';
|
||||
import type { ResultCallback } from '../errors.js';
|
||||
import type MailMessage from '../mailer/mail-message.js';
|
||||
import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
|
||||
import type { default as Mail, GetSocketCallback, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
|
||||
import type { MimeNodeEnvelope } from '../mime-node/index.js';
|
||||
/**
|
||||
* Authentication settings, either from the transport options or from the message data.
|
||||
@@ -38,9 +38,10 @@ export interface SMTPTransportAuth extends SMTPConnectionAuth {
|
||||
/**
|
||||
* Receives the socket details from getSocket, false when a new socket should be opened. The
|
||||
* object is merged into the connection options, a proxy handler provides the connected socket
|
||||
* as `connection`
|
||||
* as `connection`. The same callback type Mail hands to a transport, so that the SMTP
|
||||
* transports stay assignable to the Transport interface
|
||||
*/
|
||||
export type SMTPTransportGetSocketCallback = (err: Error | null, socketOptions?: SMTPConnectionOptions | false) => void;
|
||||
export type SMTPTransportGetSocketCallback = GetSocketCallback;
|
||||
/**
|
||||
* Custom socket provider, replaces the getSocket method of the transport
|
||||
*/
|
||||
@@ -78,6 +79,8 @@ export interface SMTPSentMessageInfo extends SMTPConnectionSendInfo, SentMessage
|
||||
accepted: string[];
|
||||
/** Recipients the server rejected */
|
||||
rejected: string[];
|
||||
/** Final server response for the message */
|
||||
response: string;
|
||||
}
|
||||
/**
|
||||
* Callback for send()
|
||||
@@ -101,7 +104,7 @@ declare class SMTPTransport extends EventEmitter {
|
||||
/**
|
||||
* The Mail instance using this transport, assigned by Mail
|
||||
*/
|
||||
mailer?: Mail<SMTPSentMessageInfo> | undefined;
|
||||
mailer?: Mail<SMTPSentMessageInfo, SMTPTransportOptions> | undefined;
|
||||
constructor(options?: SMTPTransportOptions | string);
|
||||
/**
|
||||
* Placeholder function for creating proxy sockets. This method immediatelly returns
|
||||
@@ -118,7 +121,7 @@ declare class SMTPTransport extends EventEmitter {
|
||||
* @param mail Mail object
|
||||
* @param callback Callback function
|
||||
*/
|
||||
send(mail: MailMessage, callback: SMTPTransportSendCallback): void;
|
||||
send(mail: MailMessage<SMTPSentMessageInfo>, callback: SMTPTransportSendCallback): void;
|
||||
/**
|
||||
* Verifies SMTP configuration
|
||||
*
|
||||
@@ -139,5 +142,10 @@ declare namespace SMTPTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = SMTPSentMessageInfo;
|
||||
type AuthenticationType = SMTPTransportAuth;
|
||||
type AuthenticationTypeLogin = SMTPTransportAuth;
|
||||
type AuthenticationTypeOAuth2 = SMTPTransportAuth;
|
||||
type AuthenticationTypeCustom = SMTPTransportAuth;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as SMTPTransport` and `import SMTPTransport = require()` */
|
||||
export type { SMTPTransportOptions as Options, SendMailOptions as MailOptions, SMTPSentMessageInfo as SentMessageInfo, SMTPTransportAuth as AuthenticationType, SMTPTransportAuth as AuthenticationTypeLogin, SMTPTransportAuth as AuthenticationTypeOAuth2, SMTPTransportAuth as AuthenticationTypeCustom };
|
||||
export default SMTPTransport;
|
||||
+9
-7
@@ -151,7 +151,7 @@ class SMTPTransport extends EventEmitter {
|
||||
cleanupPerCallAuth();
|
||||
// still have not returned, this means we have an unexpected connection close
|
||||
const err = new Error('Unexpected socket close');
|
||||
if (connection && connection._socket && connection._socket.upgrading) {
|
||||
if (connection && connection.upgrading) {
|
||||
// starttls connection errors
|
||||
err.code = errors.ETLS;
|
||||
}
|
||||
@@ -241,9 +241,11 @@ class SMTPTransport extends EventEmitter {
|
||||
callback = shared.callbackPromise(resolve, reject);
|
||||
});
|
||||
}
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
this.getSocket(this.options, (err, socketOptions) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
let options = this.options;
|
||||
if (socketOptions && socketOptions.connection) {
|
||||
@@ -273,7 +275,7 @@ class SMTPTransport extends EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
connection.once('end', () => {
|
||||
if (returned) {
|
||||
@@ -281,7 +283,7 @@ class SMTPTransport extends EventEmitter {
|
||||
}
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
return callback(new Error('Connection closed'));
|
||||
return done(new Error('Connection closed'));
|
||||
});
|
||||
const finalize = () => {
|
||||
if (returned) {
|
||||
@@ -290,7 +292,7 @@ class SMTPTransport extends EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.quit();
|
||||
return callback(null, true);
|
||||
return done(null, true);
|
||||
};
|
||||
connection.connect(() => {
|
||||
if (returned) {
|
||||
@@ -306,7 +308,7 @@ class SMTPTransport extends EventEmitter {
|
||||
if (err) {
|
||||
returned = true;
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
finalize();
|
||||
});
|
||||
@@ -317,7 +319,7 @@ class SMTPTransport extends EventEmitter {
|
||||
returned = true;
|
||||
cleanupPerCallAuth();
|
||||
connection.close();
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
else {
|
||||
finalize();
|
||||
|
||||
+2
@@ -60,4 +60,6 @@ declare namespace StreamTransport {
|
||||
type MailOptions = SendMailOptions;
|
||||
type SentMessageInfo = StreamSentMessageInfo;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as StreamTransport` and `import StreamTransport = require()` */
|
||||
export type { StreamTransportOptions as Options, SendMailOptions as MailOptions, StreamSentMessageInfo as SentMessageInfo };
|
||||
export default StreamTransport;
|
||||
+11
-3
@@ -1,6 +1,7 @@
|
||||
import { Stream } from 'node:stream';
|
||||
import crypto from 'node:crypto';
|
||||
import * as shared from '../shared/index.js';
|
||||
import type { ResultCallback } from '../errors.js';
|
||||
import type { OutgoingHttpHeaders } from 'node:http';
|
||||
/**
|
||||
* Receives the result of a provisionCallback run: an error, or the new access token and
|
||||
@@ -13,9 +14,11 @@ export type XOAuth2ProvisionResultCallback = (err: Error | null, accessToken?: s
|
||||
*/
|
||||
export type XOAuth2ProvisionCallback = (user: string, renew: boolean, callback: XOAuth2ProvisionResultCallback) => void;
|
||||
/**
|
||||
* Receives an access token, or the error that prevented generating one
|
||||
* Receives an access token, or the error that prevented generating one. Declared with a
|
||||
* required token, the way @types/nodemailer declared it, the error path hands over the
|
||||
* error alone
|
||||
*/
|
||||
export type XOAuth2TokenCallback = (err: Error | null, accessToken?: string) => void;
|
||||
export type XOAuth2TokenCallback = (err: Error | null, accessToken: string) => void;
|
||||
/**
|
||||
* A private key accepted by crypto.createSign().sign()
|
||||
*/
|
||||
@@ -79,7 +82,7 @@ export interface XOAuth2Token {
|
||||
*/
|
||||
export interface XOAuth2QueuedRequest {
|
||||
renew: boolean;
|
||||
callback: XOAuth2TokenCallback;
|
||||
callback: ResultCallback<string>;
|
||||
}
|
||||
/**
|
||||
* XOAUTH2 access_token generator for Gmail.
|
||||
@@ -181,11 +184,16 @@ declare class XOAuth2 extends Stream {
|
||||
[key: string]: any;
|
||||
}): string;
|
||||
}
|
||||
/** The extra request settings of the token request, the customHeaders and customParams options */
|
||||
export type XOAuth2RequestParams = Pick<XOAuth2Options, 'customHeaders' | 'customParams'>;
|
||||
/**
|
||||
* Type aliases in the layout of @types/nodemailer, so `XOAuth2.Options` style references keep working
|
||||
*/
|
||||
declare namespace XOAuth2 {
|
||||
type Options = XOAuth2Options;
|
||||
type Token = XOAuth2Token;
|
||||
type RequestParams = XOAuth2RequestParams;
|
||||
}
|
||||
/** The same aliases as module level exports, for `import * as XOAuth2` and `import XOAuth2 = require()` */
|
||||
export type { XOAuth2Options as Options, XOAuth2Token as Token, XOAuth2RequestParams as RequestParams };
|
||||
export default XOAuth2;
|
||||
+14
-10
@@ -73,6 +73,8 @@ class XOAuth2 extends Stream {
|
||||
* @param callback Callback function with error object and token string
|
||||
*/
|
||||
getToken(renew, callback) {
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) {
|
||||
this.logger.debug({
|
||||
tnx: 'OAUTH2',
|
||||
@@ -98,11 +100,11 @@ class XOAuth2 extends Stream {
|
||||
}, 'Cannot renew access token for %s: No refresh mechanism available', this.options.user);
|
||||
const err = new Error("Can't create new access token for user");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
// If renewal already in progress, queue this request instead of starting another
|
||||
if (this.renewing) {
|
||||
this.renewalQueue.push({ renew, callback });
|
||||
this.renewalQueue.push({ renew, callback: done });
|
||||
return;
|
||||
}
|
||||
this.renewing = true;
|
||||
@@ -127,7 +129,7 @@ class XOAuth2 extends Stream {
|
||||
}, 'Generated new Access Token for %s', this.options.user);
|
||||
}
|
||||
// Complete original request
|
||||
callback(err, accessToken);
|
||||
done(err, accessToken);
|
||||
};
|
||||
if (this.provisionCallback) {
|
||||
this.provisionCallback(this.options.user, !!renew, (err, accessToken, expires) => {
|
||||
@@ -166,6 +168,8 @@ class XOAuth2 extends Stream {
|
||||
* @param callback Callback function with error object and token string
|
||||
*/
|
||||
generateToken(callback) {
|
||||
// the error paths hand over the error alone
|
||||
const done = callback;
|
||||
let urlOptions;
|
||||
let loggedUrlOptions;
|
||||
if (this.options.serviceClient) {
|
||||
@@ -186,7 +190,7 @@ class XOAuth2 extends Stream {
|
||||
catch (_err) {
|
||||
const err = new Error("Can't generate token. Check your auth options");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
urlOptions = {
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||||
@@ -201,7 +205,7 @@ class XOAuth2 extends Stream {
|
||||
if (!this.options.refreshToken) {
|
||||
const err = new Error("Can't create new access token for user");
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
// web app - https://developers.google.com/identity/protocols/OAuth2WebServer
|
||||
urlOptions = {
|
||||
@@ -227,13 +231,13 @@ class XOAuth2 extends Stream {
|
||||
this.postRequest(this.options.accessUrl, urlOptions, this.options, (error, body) => {
|
||||
let data;
|
||||
if (error) {
|
||||
return callback(error);
|
||||
return done(error);
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(body.toString());
|
||||
}
|
||||
catch (E) {
|
||||
return callback(E);
|
||||
return done(E);
|
||||
}
|
||||
if (!data || typeof data !== 'object') {
|
||||
this.logger.debug({
|
||||
@@ -243,7 +247,7 @@ class XOAuth2 extends Stream {
|
||||
}, 'Response: %s', (body || '').toString());
|
||||
const err = new Error('Invalid authentication response');
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
const logData = Object.assign({}, data);
|
||||
if (logData.access_token) {
|
||||
@@ -265,7 +269,7 @@ class XOAuth2 extends Stream {
|
||||
}
|
||||
const err = new Error(errorMessage);
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
}
|
||||
if (data.access_token) {
|
||||
this.updateToken(data.access_token, data.expires_in);
|
||||
@@ -273,7 +277,7 @@ class XOAuth2 extends Stream {
|
||||
}
|
||||
const err = new Error('No access token');
|
||||
err.code = errors.EOAUTH2;
|
||||
return callback(err);
|
||||
return done(err);
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user