mirror of
https://github.com/dawidd6/action-send-mail.git
synced 2025-09-04 11:54:06 +07:00
node_modules: upgrade
This commit is contained in:
30
node_modules/nodemailer/lib/addressparser/index.js
generated
vendored
30
node_modules/nodemailer/lib/addressparser/index.js
generated
vendored
@ -7,7 +7,6 @@
|
||||
* @return {Object} Address object
|
||||
*/
|
||||
function _handleAddress(tokens) {
|
||||
let token;
|
||||
let isGroup = false;
|
||||
let state = 'text';
|
||||
let address;
|
||||
@ -23,7 +22,8 @@ function _handleAddress(tokens) {
|
||||
|
||||
// Filter out <addresses>, (comments) and regular text
|
||||
for (i = 0, len = tokens.length; i < len; i++) {
|
||||
token = tokens[i];
|
||||
let token = tokens[i];
|
||||
let prevToken = i ? tokens[i - 1] : null;
|
||||
if (token.type === 'operator') {
|
||||
switch (token.value) {
|
||||
case '<':
|
||||
@ -38,6 +38,7 @@ function _handleAddress(tokens) {
|
||||
break;
|
||||
default:
|
||||
state = 'text';
|
||||
break;
|
||||
}
|
||||
} else if (token.value) {
|
||||
if (state === 'address') {
|
||||
@ -46,7 +47,13 @@ function _handleAddress(tokens) {
|
||||
// and so will we
|
||||
token.value = token.value.replace(/^[^<]*<\s*/, '');
|
||||
}
|
||||
data[state].push(token.value);
|
||||
|
||||
if (prevToken && prevToken.noBreak && data[state].length) {
|
||||
// join values
|
||||
data[state][data[state].length - 1] += token.value;
|
||||
} else {
|
||||
data[state].push(token.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,11 +179,12 @@ class Tokenizer {
|
||||
* @return {Array} An array of operator|text tokens
|
||||
*/
|
||||
tokenize() {
|
||||
let chr,
|
||||
list = [];
|
||||
let list = [];
|
||||
|
||||
for (let i = 0, len = this.str.length; i < len; i++) {
|
||||
chr = this.str.charAt(i);
|
||||
this.checkChar(chr);
|
||||
let chr = this.str.charAt(i);
|
||||
let nextChr = i < len - 1 ? this.str.charAt(i + 1) : null;
|
||||
this.checkChar(chr, nextChr);
|
||||
}
|
||||
|
||||
this.list.forEach(node => {
|
||||
@ -194,7 +202,7 @@ class Tokenizer {
|
||||
*
|
||||
* @param {String} chr Character from the address field
|
||||
*/
|
||||
checkChar(chr) {
|
||||
checkChar(chr, nextChr) {
|
||||
if (this.escaped) {
|
||||
// ignore next condition blocks
|
||||
} else if (chr === this.operatorExpecting) {
|
||||
@ -202,10 +210,16 @@ class Tokenizer {
|
||||
type: 'operator',
|
||||
value: chr
|
||||
};
|
||||
|
||||
if (nextChr && ![' ', '\t', '\r', '\n', ',', ';'].includes(nextChr)) {
|
||||
this.node.noBreak = true;
|
||||
}
|
||||
|
||||
this.list.push(this.node);
|
||||
this.node = null;
|
||||
this.operatorExpecting = '';
|
||||
this.escaped = false;
|
||||
|
||||
return;
|
||||
} else if (!this.operatorExpecting && chr in this.operators) {
|
||||
this.node = {
|
||||
|
2
node_modules/nodemailer/lib/dkim/sign.js
generated
vendored
2
node_modules/nodemailer/lib/dkim/sign.js
generated
vendored
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const punycode = require('punycode');
|
||||
const punycode = require('../punycode');
|
||||
const mimeFuncs = require('../mime-funcs');
|
||||
const crypto = require('crypto');
|
||||
|
||||
|
5
node_modules/nodemailer/lib/fetch/index.js
generated
vendored
5
node_modules/nodemailer/lib/fetch/index.js
generated
vendored
@ -7,6 +7,7 @@ const zlib = require('zlib');
|
||||
const PassThrough = require('stream').PassThrough;
|
||||
const Cookies = require('./cookies');
|
||||
const packageData = require('../../package.json');
|
||||
const net = require('net');
|
||||
|
||||
const MAX_REDIRECTS = 5;
|
||||
|
||||
@ -131,6 +132,10 @@ function nmfetch(url, options) {
|
||||
});
|
||||
}
|
||||
|
||||
if (parsed.protocol === 'https:' && parsed.hostname && parsed.hostname !== reqOptions.host && !net.isIP(parsed.hostname) && !reqOptions.servername) {
|
||||
reqOptions.servername = parsed.hostname;
|
||||
}
|
||||
|
||||
try {
|
||||
req = handler.request(reqOptions);
|
||||
} catch (E) {
|
||||
|
31
node_modules/nodemailer/lib/mail-composer/index.js
generated
vendored
31
node_modules/nodemailer/lib/mail-composer/index.js
generated
vendored
@ -4,6 +4,7 @@
|
||||
|
||||
const MimeNode = require('../mime-node');
|
||||
const mimeFuncs = require('../mime-funcs');
|
||||
const parseDataURI = require('../shared').parseDataURI;
|
||||
|
||||
/**
|
||||
* Creates the object for composing a MimeNode instance out from the mail options
|
||||
@ -91,9 +92,13 @@ class MailComposer {
|
||||
attachment = this._processDataUrl(attachment);
|
||||
}
|
||||
|
||||
let contentType = attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin');
|
||||
let isImage = /^image\//i.test(contentType);
|
||||
let contentDisposition = attachment.contentDisposition || (isMessageNode || (isImage && attachment.cid) ? 'inline' : 'attachment');
|
||||
|
||||
data = {
|
||||
contentType: attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin'),
|
||||
contentDisposition: attachment.contentDisposition || (isMessageNode ? 'inline' : 'attachment'),
|
||||
contentType,
|
||||
contentDisposition,
|
||||
contentTransferEncoding: 'contentTransferEncoding' in attachment ? attachment.contentTransferEncoding : 'base64'
|
||||
};
|
||||
|
||||
@ -506,7 +511,10 @@ class MailComposer {
|
||||
}
|
||||
|
||||
if (!/^text\//i.test(element.contentType) || element.contentDisposition) {
|
||||
node.setHeader('Content-Disposition', element.contentDisposition || (element.cid ? 'inline' : 'attachment'));
|
||||
node.setHeader(
|
||||
'Content-Disposition',
|
||||
element.contentDisposition || (element.cid && /^image\//i.test(element.contentType) ? 'inline' : 'attachment')
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof element.content === 'string' && !['utf8', 'usascii', 'ascii'].includes(encoding)) {
|
||||
@ -530,12 +538,17 @@ class MailComposer {
|
||||
* @return {Object} Parsed element
|
||||
*/
|
||||
_processDataUrl(element) {
|
||||
let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
|
||||
if (!parts) {
|
||||
let parsedDataUri;
|
||||
if ((element.path || element.href).match(/^data:/)) {
|
||||
parsedDataUri = parseDataURI(element.path || element.href);
|
||||
}
|
||||
|
||||
if (!parsedDataUri) {
|
||||
return element;
|
||||
}
|
||||
|
||||
element.content = /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]));
|
||||
element.content = parsedDataUri.data;
|
||||
element.contentType = element.contentType || parsedDataUri.contentType;
|
||||
|
||||
if ('path' in element) {
|
||||
element.path = false;
|
||||
@ -545,12 +558,6 @@ class MailComposer {
|
||||
element.href = false;
|
||||
}
|
||||
|
||||
parts[1].split(';').forEach(item => {
|
||||
if (/^\w+\/[^/]+$/i.test(item)) {
|
||||
element.contentType = element.contentType || item.toLowerCase();
|
||||
}
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
32
node_modules/nodemailer/lib/mailer/index.js
generated
vendored
32
node_modules/nodemailer/lib/mailer/index.js
generated
vendored
@ -137,7 +137,7 @@ class Mail extends EventEmitter {
|
||||
* @param {Object} data E-data description
|
||||
* @param {Function?} callback Callback to run once the sending succeeded or failed
|
||||
*/
|
||||
sendMail(data, callback) {
|
||||
sendMail(data, callback = null) {
|
||||
let promise;
|
||||
|
||||
if (!callback) {
|
||||
@ -395,21 +395,23 @@ class Mail extends EventEmitter {
|
||||
return callback(err);
|
||||
}
|
||||
let cidCounter = 0;
|
||||
html = (html || '').toString().replace(/(<img\b[^>]* src\s*=[\s"']*)(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
|
||||
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
|
||||
if (!mail.data.attachments) {
|
||||
mail.data.attachments = [];
|
||||
}
|
||||
if (!Array.isArray(mail.data.attachments)) {
|
||||
mail.data.attachments = [].concat(mail.data.attachments || []);
|
||||
}
|
||||
mail.data.attachments.push({
|
||||
path: dataUri,
|
||||
cid,
|
||||
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
|
||||
html = (html || '')
|
||||
.toString()
|
||||
.replace(/(<img\b[^<>]{0,1024} src\s{0,20}=[\s"']{0,20})(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
|
||||
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
|
||||
if (!mail.data.attachments) {
|
||||
mail.data.attachments = [];
|
||||
}
|
||||
if (!Array.isArray(mail.data.attachments)) {
|
||||
mail.data.attachments = [].concat(mail.data.attachments || []);
|
||||
}
|
||||
mail.data.attachments.push({
|
||||
path: dataUri,
|
||||
cid,
|
||||
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
|
||||
});
|
||||
return prefix + 'cid:' + cid;
|
||||
});
|
||||
return prefix + 'cid:' + cid;
|
||||
});
|
||||
mail.data.html = html;
|
||||
callback();
|
||||
});
|
||||
|
6
node_modules/nodemailer/lib/mime-funcs/index.js
generated
vendored
6
node_modules/nodemailer/lib/mime-funcs/index.js
generated
vendored
@ -84,6 +84,12 @@ module.exports = {
|
||||
let lpart = '';
|
||||
for (let i = 0, len = encodedStr.length; i < len; i++) {
|
||||
let chr = encodedStr.charAt(i);
|
||||
|
||||
if (/[\ud83c\ud83d\ud83e]/.test(chr) && i < len - 1) {
|
||||
// composite emoji byte, so add the next byte as well
|
||||
chr += encodedStr.charAt(++i);
|
||||
}
|
||||
|
||||
// check if we can add this character to the existing string
|
||||
// without breaking byte length limit
|
||||
if (Buffer.byteLength(lpart + chr) <= maxLength || i === 0) {
|
||||
|
2
node_modules/nodemailer/lib/mime-funcs/mime-types.js
generated
vendored
2
node_modules/nodemailer/lib/mime-funcs/mime-types.js
generated
vendored
@ -44,6 +44,7 @@ const mimeTypes = new Map([
|
||||
['application/fractals', 'fif'],
|
||||
['application/freeloader', 'frl'],
|
||||
['application/futuresplash', 'spl'],
|
||||
['application/geo+json', 'geojson'],
|
||||
['application/gnutar', 'tgz'],
|
||||
['application/groupwise', 'vew'],
|
||||
['application/hlp', 'hlp'],
|
||||
@ -1287,6 +1288,7 @@ const extensions = new Map([
|
||||
['gac', 'application/vnd.groove-account'],
|
||||
['gdl', 'model/vnd.gdl'],
|
||||
['geo', 'application/vnd.dynageo'],
|
||||
['geojson', 'application/geo+json'],
|
||||
['gex', 'application/vnd.geometry-explorer'],
|
||||
['ggb', 'application/vnd.geogebra.file'],
|
||||
['ggt', 'application/vnd.geogebra.tool'],
|
||||
|
32
node_modules/nodemailer/lib/mime-node/index.js
generated
vendored
32
node_modules/nodemailer/lib/mime-node/index.js
generated
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const punycode = require('punycode');
|
||||
const punycode = require('../punycode');
|
||||
const PassThrough = require('stream').PassThrough;
|
||||
const shared = require('../shared');
|
||||
|
||||
@ -497,6 +497,15 @@ class MimeNode {
|
||||
if (!this.getHeader('MIME-Version')) {
|
||||
this.setHeader('MIME-Version', '1.0');
|
||||
}
|
||||
|
||||
// Ensure that Content-Type is the last header for the root node
|
||||
for (let i = this._headers.length - 2; i >= 0; i--) {
|
||||
let header = this._headers[i];
|
||||
if (header.key === 'Content-Type') {
|
||||
this._headers.splice(i, 1);
|
||||
this._headers.push(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._headers.forEach(header => {
|
||||
@ -950,7 +959,15 @@ class MimeNode {
|
||||
if (content._resolvedValue) {
|
||||
// pass string or buffer content as a stream
|
||||
contentStream = new PassThrough();
|
||||
setImmediate(() => contentStream.end(content._resolvedValue));
|
||||
|
||||
setImmediate(() => {
|
||||
try {
|
||||
contentStream.end(content._resolvedValue);
|
||||
} catch (err) {
|
||||
contentStream.emit('error', err);
|
||||
}
|
||||
});
|
||||
|
||||
return contentStream;
|
||||
} else if (typeof content.pipe === 'function') {
|
||||
// assume as stream
|
||||
@ -974,7 +991,14 @@ class MimeNode {
|
||||
} else {
|
||||
// pass string or buffer content as a stream
|
||||
contentStream = new PassThrough();
|
||||
setImmediate(() => contentStream.end(content || ''));
|
||||
|
||||
setImmediate(() => {
|
||||
try {
|
||||
contentStream.end(content || '');
|
||||
} catch (err) {
|
||||
contentStream.emit('error', err);
|
||||
}
|
||||
});
|
||||
return contentStream;
|
||||
}
|
||||
}
|
||||
@ -1218,7 +1242,7 @@ class MimeNode {
|
||||
* @returns {String} Mime word encoded string if needed
|
||||
*/
|
||||
_encodeAddressName(name) {
|
||||
if (!/^[\w ']*$/.test(name)) {
|
||||
if (!/^[\w ]*$/.test(name)) {
|
||||
if (/^[\x20-\x7e]*$/.test(name)) {
|
||||
return '"' + name.replace(/([\\"])/g, '\\$1') + '"';
|
||||
} else {
|
||||
|
19
node_modules/nodemailer/lib/nodemailer.js
generated
vendored
19
node_modules/nodemailer/lib/nodemailer.js
generated
vendored
@ -13,6 +13,7 @@ const packageData = require('../package.json');
|
||||
|
||||
const ETHEREAL_API = (process.env.ETHEREAL_API || 'https://api.nodemailer.com').replace(/\/+$/, '');
|
||||
const ETHEREAL_WEB = (process.env.ETHEREAL_WEB || 'https://ethereal.email').replace(/\/+$/, '');
|
||||
const ETHEREAL_API_KEY = (process.env.ETHEREAL_API_KEY || '').replace(/\s*/g, '') || null;
|
||||
const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes((process.env.ETHEREAL_CACHE || 'yes').toString().trim().toLowerCase());
|
||||
|
||||
let testAccount = false;
|
||||
@ -79,15 +80,21 @@ module.exports.createTestAccount = function (apiUrl, callback) {
|
||||
let chunks = [];
|
||||
let chunklen = 0;
|
||||
|
||||
let requestHeaders = {};
|
||||
let requestBody = {
|
||||
requestor: packageData.name,
|
||||
version: packageData.version
|
||||
};
|
||||
|
||||
if (ETHEREAL_API_KEY) {
|
||||
requestHeaders.Authorization = 'Bearer ' + ETHEREAL_API_KEY;
|
||||
}
|
||||
|
||||
let req = nmfetch(apiUrl + '/user', {
|
||||
contentType: 'application/json',
|
||||
method: 'POST',
|
||||
body: Buffer.from(
|
||||
JSON.stringify({
|
||||
requestor: packageData.name,
|
||||
version: packageData.version
|
||||
})
|
||||
)
|
||||
headers: requestHeaders,
|
||||
body: Buffer.from(JSON.stringify(requestBody))
|
||||
});
|
||||
|
||||
req.on('readable', () => {
|
||||
|
460
node_modules/nodemailer/lib/punycode/index.js
generated
vendored
Normal file
460
node_modules/nodemailer/lib/punycode/index.js
generated
vendored
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
|
||||
Copied from https://github.com/mathiasbynens/punycode.js/blob/ef3505c8abb5143a00d53ce59077c9f7f4b2ac47/punycode.js
|
||||
|
||||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
/* eslint callback-return: 0, no-bitwise: 0, eqeqeq: 0, prefer-arrow-callback: 0, object-shorthand: 0 */
|
||||
|
||||
'use strict';
|
||||
|
||||
/** Highest positive signed 32-bit float value */
|
||||
const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
|
||||
|
||||
/** Bootstring parameters */
|
||||
const base = 36;
|
||||
const tMin = 1;
|
||||
const tMax = 26;
|
||||
const skew = 38;
|
||||
const damp = 700;
|
||||
const initialBias = 72;
|
||||
const initialN = 128; // 0x80
|
||||
const delimiter = '-'; // '\x2D'
|
||||
|
||||
/** Regular expressions */
|
||||
const regexPunycode = /^xn--/;
|
||||
const regexNonASCII = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too.
|
||||
const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
|
||||
|
||||
/** Error messages */
|
||||
const errors = {
|
||||
overflow: 'Overflow: input needs wider integers to process',
|
||||
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
||||
'invalid-input': 'Invalid input'
|
||||
};
|
||||
|
||||
/** Convenience shortcuts */
|
||||
const baseMinusTMin = base - tMin;
|
||||
const floor = Math.floor;
|
||||
const stringFromCharCode = String.fromCharCode;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* A generic error utility function.
|
||||
* @private
|
||||
* @param {String} type The error type.
|
||||
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
||||
*/
|
||||
function error(type) {
|
||||
throw new RangeError(errors[type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic `Array#map` utility function.
|
||||
* @private
|
||||
* @param {Array} array The array to iterate over.
|
||||
* @param {Function} callback The function that gets called for every array
|
||||
* item.
|
||||
* @returns {Array} A new array of values returned by the callback function.
|
||||
*/
|
||||
function map(array, callback) {
|
||||
const result = [];
|
||||
let length = array.length;
|
||||
while (length--) {
|
||||
result[length] = callback(array[length]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple `Array#map`-like wrapper to work with domain name strings or email
|
||||
* addresses.
|
||||
* @private
|
||||
* @param {String} domain The domain name or email address.
|
||||
* @param {Function} callback The function that gets called for every
|
||||
* character.
|
||||
* @returns {String} A new string of characters returned by the callback
|
||||
* function.
|
||||
*/
|
||||
function mapDomain(domain, callback) {
|
||||
const parts = domain.split('@');
|
||||
let result = '';
|
||||
if (parts.length > 1) {
|
||||
// In email addresses, only the domain name should be punycoded. Leave
|
||||
// the local part (i.e. everything up to `@`) intact.
|
||||
result = parts[0] + '@';
|
||||
domain = parts[1];
|
||||
}
|
||||
// Avoid `split(regex)` for IE8 compatibility. See #17.
|
||||
domain = domain.replace(regexSeparators, '\x2E');
|
||||
const labels = domain.split('.');
|
||||
const encoded = map(labels, callback).join('.');
|
||||
return result + encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array containing the numeric code points of each Unicode
|
||||
* character in the string. While JavaScript uses UCS-2 internally,
|
||||
* this function will convert a pair of surrogate halves (each of which
|
||||
* UCS-2 exposes as separate characters) into a single code point,
|
||||
* matching UTF-16.
|
||||
* @see `punycode.ucs2.encode`
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode.ucs2
|
||||
* @name decode
|
||||
* @param {String} string The Unicode input string (UCS-2).
|
||||
* @returns {Array} The new array of code points.
|
||||
*/
|
||||
function ucs2decode(string) {
|
||||
const output = [];
|
||||
let counter = 0;
|
||||
const length = string.length;
|
||||
while (counter < length) {
|
||||
const value = string.charCodeAt(counter++);
|
||||
if (value >= 0xd800 && value <= 0xdbff && counter < length) {
|
||||
// It's a high surrogate, and there is a next character.
|
||||
const extra = string.charCodeAt(counter++);
|
||||
if ((extra & 0xfc00) == 0xdc00) {
|
||||
// Low surrogate.
|
||||
output.push(((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
||||
} else {
|
||||
// It's an unmatched surrogate; only append this code unit, in case the
|
||||
// next code unit is the high surrogate of a surrogate pair.
|
||||
output.push(value);
|
||||
counter--;
|
||||
}
|
||||
} else {
|
||||
output.push(value);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string based on an array of numeric code points.
|
||||
* @see `punycode.ucs2.decode`
|
||||
* @memberOf punycode.ucs2
|
||||
* @name encode
|
||||
* @param {Array} codePoints The array of numeric code points.
|
||||
* @returns {String} The new Unicode string (UCS-2).
|
||||
*/
|
||||
const ucs2encode = codePoints => String.fromCodePoint(...codePoints);
|
||||
|
||||
/**
|
||||
* Converts a basic code point into a digit/integer.
|
||||
* @see `digitToBasic()`
|
||||
* @private
|
||||
* @param {Number} codePoint The basic numeric code point value.
|
||||
* @returns {Number} The numeric value of a basic code point (for use in
|
||||
* representing integers) in the range `0` to `base - 1`, or `base` if
|
||||
* the code point does not represent a value.
|
||||
*/
|
||||
const basicToDigit = function (codePoint) {
|
||||
if (codePoint >= 0x30 && codePoint < 0x3a) {
|
||||
return 26 + (codePoint - 0x30);
|
||||
}
|
||||
if (codePoint >= 0x41 && codePoint < 0x5b) {
|
||||
return codePoint - 0x41;
|
||||
}
|
||||
if (codePoint >= 0x61 && codePoint < 0x7b) {
|
||||
return codePoint - 0x61;
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a digit/integer into a basic code point.
|
||||
* @see `basicToDigit()`
|
||||
* @private
|
||||
* @param {Number} digit The numeric value of a basic code point.
|
||||
* @returns {Number} The basic code point whose value (when used for
|
||||
* representing integers) is `digit`, which needs to be in the range
|
||||
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
||||
* used; else, the lowercase form is used. The behavior is undefined
|
||||
* if `flag` is non-zero and `digit` has no uppercase form.
|
||||
*/
|
||||
const digitToBasic = function (digit, flag) {
|
||||
// 0..25 map to ASCII a..z or A..Z
|
||||
// 26..35 map to ASCII 0..9
|
||||
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bias adaptation function as per section 3.4 of RFC 3492.
|
||||
* https://tools.ietf.org/html/rfc3492#section-3.4
|
||||
* @private
|
||||
*/
|
||||
const adapt = function (delta, numPoints, firstTime) {
|
||||
let k = 0;
|
||||
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
||||
delta += floor(delta / numPoints);
|
||||
for (; /* no initialization */ delta > (baseMinusTMin * tMax) >> 1; k += base) {
|
||||
delta = floor(delta / baseMinusTMin);
|
||||
}
|
||||
return floor(k + ((baseMinusTMin + 1) * delta) / (delta + skew));
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
||||
* symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycode string of ASCII-only symbols.
|
||||
* @returns {String} The resulting string of Unicode symbols.
|
||||
*/
|
||||
const decode = function (input) {
|
||||
// Don't use UCS-2.
|
||||
const output = [];
|
||||
const inputLength = input.length;
|
||||
let i = 0;
|
||||
let n = initialN;
|
||||
let bias = initialBias;
|
||||
|
||||
// Handle the basic code points: let `basic` be the number of input code
|
||||
// points before the last delimiter, or `0` if there is none, then copy
|
||||
// the first basic code points to the output.
|
||||
|
||||
let basic = input.lastIndexOf(delimiter);
|
||||
if (basic < 0) {
|
||||
basic = 0;
|
||||
}
|
||||
|
||||
for (let j = 0; j < basic; ++j) {
|
||||
// if it's not a basic code point
|
||||
if (input.charCodeAt(j) >= 0x80) {
|
||||
error('not-basic');
|
||||
}
|
||||
output.push(input.charCodeAt(j));
|
||||
}
|
||||
|
||||
// Main decoding loop: start just after the last delimiter if any basic code
|
||||
// points were copied; start at the beginning otherwise.
|
||||
|
||||
for (let index = basic > 0 ? basic + 1 : 0; index < inputLength /* no final expression */; ) {
|
||||
// `index` is the index of the next character to be consumed.
|
||||
// Decode a generalized variable-length integer into `delta`,
|
||||
// which gets added to `i`. The overflow checking is easier
|
||||
// if we increase `i` as we go, then subtract off its starting
|
||||
// value at the end to obtain `delta`.
|
||||
const oldi = i;
|
||||
for (let w = 1, k = base /* no condition */; ; k += base) {
|
||||
if (index >= inputLength) {
|
||||
error('invalid-input');
|
||||
}
|
||||
|
||||
const digit = basicToDigit(input.charCodeAt(index++));
|
||||
|
||||
if (digit >= base) {
|
||||
error('invalid-input');
|
||||
}
|
||||
if (digit > floor((maxInt - i) / w)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
i += digit * w;
|
||||
const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
|
||||
|
||||
if (digit < t) {
|
||||
break;
|
||||
}
|
||||
|
||||
const baseMinusT = base - t;
|
||||
if (w > floor(maxInt / baseMinusT)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
w *= baseMinusT;
|
||||
}
|
||||
|
||||
const out = output.length + 1;
|
||||
bias = adapt(i - oldi, out, oldi == 0);
|
||||
|
||||
// `i` was supposed to wrap around from `out` to `0`,
|
||||
// incrementing `n` each time, so we'll fix that now:
|
||||
if (floor(i / out) > maxInt - n) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
n += floor(i / out);
|
||||
i %= out;
|
||||
|
||||
// Insert `n` at position `i` of the output.
|
||||
output.splice(i++, 0, n);
|
||||
}
|
||||
|
||||
return String.fromCodePoint(...output);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string of Unicode symbols (e.g. a domain name label) to a
|
||||
* Punycode string of ASCII-only symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The string of Unicode symbols.
|
||||
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
||||
*/
|
||||
const encode = function (input) {
|
||||
const output = [];
|
||||
|
||||
// Convert the input in UCS-2 to an array of Unicode code points.
|
||||
input = ucs2decode(input);
|
||||
|
||||
// Cache the length.
|
||||
const inputLength = input.length;
|
||||
|
||||
// Initialize the state.
|
||||
let n = initialN;
|
||||
let delta = 0;
|
||||
let bias = initialBias;
|
||||
|
||||
// Handle the basic code points.
|
||||
for (const currentValue of input) {
|
||||
if (currentValue < 0x80) {
|
||||
output.push(stringFromCharCode(currentValue));
|
||||
}
|
||||
}
|
||||
|
||||
const basicLength = output.length;
|
||||
let handledCPCount = basicLength;
|
||||
|
||||
// `handledCPCount` is the number of code points that have been handled;
|
||||
// `basicLength` is the number of basic code points.
|
||||
|
||||
// Finish the basic string with a delimiter unless it's empty.
|
||||
if (basicLength) {
|
||||
output.push(delimiter);
|
||||
}
|
||||
|
||||
// Main encoding loop:
|
||||
while (handledCPCount < inputLength) {
|
||||
// All non-basic code points < n have been handled already. Find the next
|
||||
// larger one:
|
||||
let m = maxInt;
|
||||
for (const currentValue of input) {
|
||||
if (currentValue >= n && currentValue < m) {
|
||||
m = currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
||||
// but guard against overflow.
|
||||
const handledCPCountPlusOne = handledCPCount + 1;
|
||||
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
delta += (m - n) * handledCPCountPlusOne;
|
||||
n = m;
|
||||
|
||||
for (const currentValue of input) {
|
||||
if (currentValue < n && ++delta > maxInt) {
|
||||
error('overflow');
|
||||
}
|
||||
if (currentValue === n) {
|
||||
// Represent delta as a generalized variable-length integer.
|
||||
let q = delta;
|
||||
for (let k = base /* no condition */; ; k += base) {
|
||||
const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
|
||||
if (q < t) {
|
||||
break;
|
||||
}
|
||||
const qMinusT = q - t;
|
||||
const baseMinusT = base - t;
|
||||
output.push(stringFromCharCode(digitToBasic(t + (qMinusT % baseMinusT), 0)));
|
||||
q = floor(qMinusT / baseMinusT);
|
||||
}
|
||||
|
||||
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
||||
bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
|
||||
delta = 0;
|
||||
++handledCPCount;
|
||||
}
|
||||
}
|
||||
|
||||
++delta;
|
||||
++n;
|
||||
}
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Punycode string representing a domain name or an email address
|
||||
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
|
||||
* it doesn't matter if you call it on a string that has already been
|
||||
* converted to Unicode.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycoded domain name or email address to
|
||||
* convert to Unicode.
|
||||
* @returns {String} The Unicode representation of the given Punycode
|
||||
* string.
|
||||
*/
|
||||
const toUnicode = function (input) {
|
||||
return mapDomain(input, function (string) {
|
||||
return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Unicode string representing a domain name or an email address to
|
||||
* Punycode. Only the non-ASCII parts of the domain name will be converted,
|
||||
* i.e. it doesn't matter if you call it with a domain that's already in
|
||||
* ASCII.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The domain name or email address to convert, as a
|
||||
* Unicode string.
|
||||
* @returns {String} The Punycode representation of the given domain name or
|
||||
* email address.
|
||||
*/
|
||||
const toASCII = function (input) {
|
||||
return mapDomain(input, function (string) {
|
||||
return regexNonASCII.test(string) ? 'xn--' + encode(string) : string;
|
||||
});
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/** Define the public API */
|
||||
const punycode = {
|
||||
/**
|
||||
* A string representing the current Punycode.js version number.
|
||||
* @memberOf punycode
|
||||
* @type String
|
||||
*/
|
||||
version: '2.3.1',
|
||||
/**
|
||||
* An object of methods to convert from JavaScript's internal character
|
||||
* representation (UCS-2) to Unicode code points, and back.
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode
|
||||
* @type Object
|
||||
*/
|
||||
ucs2: {
|
||||
decode: ucs2decode,
|
||||
encode: ucs2encode
|
||||
},
|
||||
decode: decode,
|
||||
encode: encode,
|
||||
toASCII: toASCII,
|
||||
toUnicode: toUnicode
|
||||
};
|
||||
|
||||
module.exports = punycode;
|
59
node_modules/nodemailer/lib/shared/index.js
generated
vendored
59
node_modules/nodemailer/lib/shared/index.js
generated
vendored
@ -216,8 +216,7 @@ module.exports.resolveHostname = (options, callback) => {
|
||||
|
||||
if (addresses && addresses.length && !address) {
|
||||
// there are addresses but none can be used
|
||||
let err = new Error(`Can not use IPv${addresses[0].family} addresses with current network`);
|
||||
return callback(err);
|
||||
console.warn(`Failed to resolve IPv${addresses[0].family} addresses with current network`);
|
||||
}
|
||||
|
||||
if (!address && cached) {
|
||||
@ -419,6 +418,55 @@ module.exports.callbackPromise = (resolve, reject) =>
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.parseDataURI = uri => {
|
||||
let input = uri;
|
||||
let commaPos = input.indexOf(',');
|
||||
if (!commaPos) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
let data = input.substring(commaPos + 1);
|
||||
let metaStr = input.substring('data:'.length, commaPos);
|
||||
|
||||
let encoding;
|
||||
|
||||
let metaEntries = metaStr.split(';');
|
||||
let lastMetaEntry = metaEntries.length > 1 ? metaEntries[metaEntries.length - 1] : false;
|
||||
if (lastMetaEntry && lastMetaEntry.indexOf('=') < 0) {
|
||||
encoding = lastMetaEntry.toLowerCase();
|
||||
metaEntries.pop();
|
||||
}
|
||||
|
||||
let contentType = metaEntries.shift() || 'application/octet-stream';
|
||||
let params = {};
|
||||
for (let entry of metaEntries) {
|
||||
let sep = entry.indexOf('=');
|
||||
if (sep >= 0) {
|
||||
let key = entry.substring(0, sep);
|
||||
let value = entry.substring(sep + 1);
|
||||
params[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
switch (encoding) {
|
||||
case 'base64':
|
||||
data = Buffer.from(data, 'base64');
|
||||
break;
|
||||
case 'utf8':
|
||||
data = Buffer.from(data);
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
data = Buffer.from(decodeURIComponent(data));
|
||||
} catch (err) {
|
||||
data = Buffer.from(data);
|
||||
}
|
||||
data = Buffer.from(data);
|
||||
}
|
||||
|
||||
return { data, encoding, contentType, params };
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves a String or a Buffer value for content value. Useful if the value
|
||||
* is a Stream or a file or an URL. If the value is a Stream, overwrites
|
||||
@ -471,11 +519,12 @@ module.exports.resolveContent = (data, key, callback) => {
|
||||
contentStream = nmfetch(content.path || content.href);
|
||||
return resolveStream(contentStream, callback);
|
||||
} else if (/^data:/i.test(content.path || content.href)) {
|
||||
let parts = (content.path || content.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
|
||||
if (!parts) {
|
||||
let parsedDataUri = module.exports.parseDataURI(content.path || content.href);
|
||||
|
||||
if (!parsedDataUri || !parsedDataUri.data) {
|
||||
return callback(null, Buffer.from(0));
|
||||
}
|
||||
return callback(null, /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2])));
|
||||
return callback(null, parsedDataUri.data);
|
||||
} else if (content.path) {
|
||||
return resolveStream(fs.createReadStream(content.path), callback);
|
||||
}
|
||||
|
64
node_modules/nodemailer/lib/smtp-connection/index.js
generated
vendored
64
node_modules/nodemailer/lib/smtp-connection/index.js
generated
vendored
@ -14,7 +14,7 @@ const shared = require('../shared');
|
||||
const CONNECTION_TIMEOUT = 2 * 60 * 1000; // how much to wait for the connection to be established
|
||||
const SOCKET_TIMEOUT = 10 * 60 * 1000; // how much to wait for socket inactivity before disconnecting the client
|
||||
const GREETING_TIMEOUT = 30 * 1000; // how much to wait after connection is established but SMTP greeting is not receieved
|
||||
const DNS_TIMEOUT = 30 * 1000; // how much to wait for resolveHostname
|
||||
const DNS_TIMEOUT = 30 * 1000; // how much to wait for resolveHostname
|
||||
|
||||
/**
|
||||
* Generates a SMTP connection object
|
||||
@ -58,6 +58,8 @@ class SMTPConnection extends EventEmitter {
|
||||
this.port = Number(this.options.port) || (this.secureConnection ? 465 : 587);
|
||||
this.host = this.options.host || 'localhost';
|
||||
|
||||
this.servername = this.options.servername ? this.options.servername : !net.isIP(this.host) ? this.host : false;
|
||||
|
||||
this.allowInternalNetworkInterfaces = this.options.allowInternalNetworkInterfaces || false;
|
||||
|
||||
if (typeof this.options.secure === 'undefined' && this.port === 465) {
|
||||
@ -241,6 +243,8 @@ class SMTPConnection extends EventEmitter {
|
||||
if (this.options.connection) {
|
||||
// connection is already opened
|
||||
this._socket = this.options.connection;
|
||||
setupConnectionHandlers();
|
||||
|
||||
if (this.secureConnection && !this.alreadySecured) {
|
||||
setImmediate(() =>
|
||||
this._upgradeConnection(err => {
|
||||
@ -296,6 +300,12 @@ class SMTPConnection extends EventEmitter {
|
||||
opts[key] = this.options.tls[key];
|
||||
});
|
||||
}
|
||||
|
||||
// ensure servername for SNI
|
||||
if (this.servername && !opts.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
|
||||
return shared.resolveHostname(opts, (err, resolved) => {
|
||||
if (err) {
|
||||
return setImmediate(() => this._onError(err, 'EDNS', false, 'CONN'));
|
||||
@ -404,7 +414,7 @@ class SMTPConnection extends EventEmitter {
|
||||
|
||||
if (socket && !socket.destroyed) {
|
||||
try {
|
||||
this._socket[closeMethod]();
|
||||
socket[closeMethod]();
|
||||
} catch (E) {
|
||||
// just ignore
|
||||
}
|
||||
@ -434,7 +444,7 @@ class SMTPConnection extends EventEmitter {
|
||||
}
|
||||
|
||||
if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
||||
if (this._auth.user && this._auth.pass) {
|
||||
if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) {
|
||||
this._auth.credentials = {
|
||||
user: this._auth.user,
|
||||
pass: this._auth.pass,
|
||||
@ -620,6 +630,15 @@ class SMTPConnection extends EventEmitter {
|
||||
let startTime = Date.now();
|
||||
this._setEnvelope(envelope, (err, info) => {
|
||||
if (err) {
|
||||
// create passthrough stream to consume to prevent OOM
|
||||
let stream = new PassThrough();
|
||||
if (typeof message.pipe === 'function') {
|
||||
message.pipe(stream);
|
||||
} else {
|
||||
stream.write(message);
|
||||
stream.end();
|
||||
}
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
let envelopeTime = Date.now();
|
||||
@ -817,6 +836,20 @@ class SMTPConnection extends EventEmitter {
|
||||
* @event
|
||||
*/
|
||||
_onClose() {
|
||||
let serverResponse = false;
|
||||
|
||||
if (this._remainder && this._remainder.trim()) {
|
||||
if (this.options.debug || this.options.transactionLog) {
|
||||
this.logger.debug(
|
||||
{
|
||||
tnx: 'server'
|
||||
},
|
||||
this._remainder.replace(/\r?\n$/, '')
|
||||
);
|
||||
}
|
||||
this.lastServerResponse = serverResponse = this._remainder.trim();
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
{
|
||||
tnx: 'network'
|
||||
@ -825,9 +858,11 @@ class SMTPConnection extends EventEmitter {
|
||||
);
|
||||
|
||||
if (this.upgrading && !this._destroyed) {
|
||||
return this._onError(new Error('Connection closed unexpectedly'), 'ETLS', false, 'CONN');
|
||||
return this._onError(new Error('Connection closed unexpectedly'), 'ETLS', serverResponse, 'CONN');
|
||||
} else if (![this._actionGreeting, this.close].includes(this._responseActions[0]) && !this._destroyed) {
|
||||
return this._onError(new Error('Connection closed unexpectedly'), 'ECONNECTION', false, 'CONN');
|
||||
return this._onError(new Error('Connection closed unexpectedly'), 'ECONNECTION', serverResponse, 'CONN');
|
||||
} else if (/^[45]\d{2}\b/.test(serverResponse)) {
|
||||
return this._onError(new Error('Connection closed unexpectedly'), 'ECONNECTION', serverResponse, 'CONN');
|
||||
}
|
||||
|
||||
this._destroy();
|
||||
@ -888,6 +923,11 @@ class SMTPConnection extends EventEmitter {
|
||||
opts[key] = this.options.tls[key];
|
||||
});
|
||||
|
||||
// ensure servername for SNI
|
||||
if (this.servername && !opts.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
|
||||
this.upgrading = true;
|
||||
// tls.connect is not an asynchronous function however it may still throw errors and requires to be wrapped with try/catch
|
||||
try {
|
||||
@ -944,14 +984,14 @@ class SMTPConnection extends EventEmitter {
|
||||
|
||||
if (!str.trim()) {
|
||||
// skip unexpected empty lines
|
||||
setImmediate(() => this._processResponse(true));
|
||||
setImmediate(() => this._processResponse());
|
||||
}
|
||||
|
||||
let action = this._responseActions.shift();
|
||||
|
||||
if (typeof action === 'function') {
|
||||
action.call(this, str);
|
||||
setImmediate(() => this._processResponse(true));
|
||||
setImmediate(() => this._processResponse());
|
||||
} else {
|
||||
return this._onError(new Error('Unexpected Response'), 'EPROTOCOL', str, 'CONN');
|
||||
}
|
||||
@ -1264,6 +1304,12 @@ class SMTPConnection extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
this._ehloLines = str
|
||||
.split(/\r?\n/)
|
||||
.map(line => line.replace(/^\d+[ -]/, '').trim())
|
||||
.filter(line => line)
|
||||
.slice(1);
|
||||
|
||||
// Detect if the server supports STARTTLS
|
||||
if (!this.secure && !this.options.ignoreTLS && (/[ -]STARTTLS\b/im.test(str) || this.options.requireTLS)) {
|
||||
this._sendCommand('STARTTLS');
|
||||
@ -1661,6 +1707,10 @@ class SMTPConnection extends EventEmitter {
|
||||
rejected: this._envelope.rejected
|
||||
};
|
||||
|
||||
if (this._ehloLines && this._ehloLines.length) {
|
||||
response.ehlo = this._ehloLines;
|
||||
}
|
||||
|
||||
if (this._envelope.rejectedErrors.length) {
|
||||
response.rejectedErrors = this._envelope.rejectedErrors;
|
||||
}
|
||||
|
96
node_modules/nodemailer/lib/well-known/services.json
generated
vendored
96
node_modules/nodemailer/lib/well-known/services.json
generated
vendored
@ -5,13 +5,20 @@
|
||||
"secure": true,
|
||||
"authMethod": "LOGIN"
|
||||
},
|
||||
|
||||
|
||||
"Aliyun": {
|
||||
"domains": ["aliyun.com"],
|
||||
"host": "smtp.aliyun.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"AOL": {
|
||||
"domains": ["aol.com"],
|
||||
"host": "smtp.aol.com",
|
||||
"port": 587
|
||||
},
|
||||
|
||||
|
||||
"Bluewin": {
|
||||
"host": "smtpauths.bluewin.ch",
|
||||
"domains": ["bluewin.ch"],
|
||||
@ -42,6 +49,22 @@
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"Forward Email": {
|
||||
"aliases": ["FE", "ForwardEmail"],
|
||||
"domains": ["forwardemail.net"],
|
||||
"host": "smtp.forwardemail.net",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"Feishu Mail": {
|
||||
"aliases": ["Feishu", "FeishuMail"],
|
||||
"domains": ["www.feishu.cn"],
|
||||
"host": "smtp.feishu.cn",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"GandiMail": {
|
||||
"aliases": ["Gandi", "Gandi Mail"],
|
||||
"host": "mail.gandi.net",
|
||||
@ -94,7 +117,10 @@
|
||||
"domains": ["ik.me", "ikmail.com", "etik.com"],
|
||||
"port": 587
|
||||
},
|
||||
|
||||
"Loopia": {
|
||||
"host": "mailcluster.loopia.se",
|
||||
"port": 465
|
||||
},
|
||||
"mail.ee": {
|
||||
"host": "smtp.mail.ee"
|
||||
},
|
||||
@ -105,6 +131,11 @@
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"Mailcatch.app": {
|
||||
"host": "sandbox-smtp.mailcatch.app",
|
||||
"port": 2525
|
||||
},
|
||||
|
||||
"Maildev": {
|
||||
"port": 1025,
|
||||
"ignoreTLS": true
|
||||
@ -127,8 +158,8 @@
|
||||
},
|
||||
|
||||
"Mailtrap": {
|
||||
"host": "smtp.mailtrap.io",
|
||||
"port": 2525
|
||||
"host": "live.smtp.mailtrap.io",
|
||||
"port": 587
|
||||
},
|
||||
|
||||
"Mandrill": {
|
||||
@ -172,6 +203,14 @@
|
||||
"port": 2525
|
||||
},
|
||||
|
||||
"Proton": {
|
||||
"aliases": ["ProtonMail", "Proton.me", "Protonmail.com", "Protonmail.ch"],
|
||||
"domains": ["proton.me", "protonmail.com", "pm.me", "protonmail.ch"],
|
||||
"host": "smtp.protonmail.ch",
|
||||
"port": 587,
|
||||
"requireTLS": true
|
||||
},
|
||||
|
||||
"qiye.aliyun": {
|
||||
"host": "smtp.mxhichina.com",
|
||||
"port": "465",
|
||||
@ -204,7 +243,8 @@
|
||||
},
|
||||
|
||||
"SendinBlue": {
|
||||
"host": "smtp-relay.sendinblue.com",
|
||||
"aliases": ["Brevo"],
|
||||
"host": "smtp-relay.brevo.com",
|
||||
"port": 587
|
||||
},
|
||||
|
||||
@ -238,6 +278,50 @@
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-SOUTH-1": {
|
||||
"host": "email-smtp.ap-south-1.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-NORTHEAST-1": {
|
||||
"host": "email-smtp.ap-northeast-1.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-NORTHEAST-2": {
|
||||
"host": "email-smtp.ap-northeast-2.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-NORTHEAST-3": {
|
||||
"host": "email-smtp.ap-northeast-3.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-SOUTHEAST-1": {
|
||||
"host": "email-smtp.ap-southeast-1.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"SES-AP-SOUTHEAST-2": {
|
||||
"host": "email-smtp.ap-southeast-2.amazonaws.com",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"Seznam": {
|
||||
"aliases": ["Seznam Email"],
|
||||
"domains": ["seznam.cz", "email.cz", "post.cz", "spoluzaci.cz"],
|
||||
"host": "smtp.seznam.cz",
|
||||
"port": 465,
|
||||
"secure": true
|
||||
},
|
||||
|
||||
"Sparkpost": {
|
||||
"aliases": ["SparkPost", "SparkPost Mail"],
|
||||
"domains": ["sparkpost.com"],
|
||||
|
Reference in New Issue
Block a user