Compare commits

...

8 Commits

Author SHA1 Message Date
Zack Schuster 94d41b2dec test/queue: improve logging & increase client timeout 2022-05-06 14:23:06 -07:00
Zack Schuster 1f3eaa1618 test/queue: refactor to differentiate between successful and failed task attempts 2022-05-06 13:42:28 -07:00
Zack Schuster 7f303733b4 chore: update readme 2022-05-06 13:06:53 -07:00
Zack Schuster cb59bb1601 chore: upgrade yarn 2022-05-06 12:58:24 -07:00
Zack Schuster 28d065e12c chore: add packageManager field to manifest 2022-05-06 12:57:25 -07:00
Zack Schuster 72fa294a7c chore: upgrade deps 2022-05-06 12:57:06 -07:00
Zack Schuster 6f061ddd6b test/auth: don't wait for server to close to fulfill connection promise 2022-05-06 12:32:33 -07:00
Zack Schuster a0eac511d5 test/queue: add failure test 2022-05-06 12:29:18 -07:00
5 changed files with 202 additions and 83 deletions

View File

@ -3,8 +3,9 @@
send emails, html and attachments (files, streams and strings) from node.js to any smtp server
## INSTALLING
npm install emailjs
```console
$ npm install emailjs # or yarn, pnpm, etc.
```
## FEATURES
@ -22,6 +23,29 @@ send emails, html and attachments (files, streams and strings) from node.js to a
- auth access to an SMTP Server
- if your service (ex: gmail) uses two-step authentication, use an application specific password
## DEVELOPMENT
issues and pull requests are welcome!
### Setup
#### node 14+
```console
$ corepack prepare # if yarn is not installed
$ yarn
```
#### node 12
```console
$ npm install --global yarn # if yarn is not installed; see https://classic.yarnpkg.com/en/docs/install
$ yarn
```
### Testing
```console
$ yarn test
```
## EXAMPLE USAGE - text only emails
```js
@ -309,12 +333,3 @@ associative array of currently supported SMTP authentication mechanisms
eleith
zackschuster
## Testing
npm install -d
npm test
## Contributions
issues and pull requests are welcome

View File

@ -15,21 +15,22 @@
"url": "http://github.com/eleith/emailjs.git"
},
"type": "module",
"packageManager": "yarn@1.22.18",
"devDependencies": {
"@ledge/configs": "23.3.23322",
"@rollup/plugin-typescript": "8.3.2",
"@types/mailparser": "3.4.0",
"@types/node": "12.12.6",
"@types/smtp-server": "3.5.7",
"@typescript-eslint/eslint-plugin": "5.21.0",
"@typescript-eslint/parser": "5.21.0",
"@typescript-eslint/eslint-plugin": "5.22.0",
"@typescript-eslint/parser": "5.22.0",
"ava": "4.2.0",
"eslint": "8.14.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-prettier": "4.0.0",
"mailparser": "3.5.0",
"prettier": "2.6.2",
"rollup": "2.70.2",
"rollup": "2.72.0",
"smtp-server": "3.11.0",
"ts-node": "10.7.0",
"tslib": "2.4.0",
@ -44,7 +45,7 @@
}
},
"resolutions": {
"nodemailer": "6.7.4"
"nodemailer": "6.7.5"
},
"engines": {
"node": ">=12"

View File

@ -46,13 +46,12 @@ function connect({
: { ssl: secure, user: 'pooh', password: 'honey' }
);
new SMTPConnection(options).connect((err) => {
server.close(() => {
if (err) {
reject(err.message);
} else {
resolve();
}
});
server.close();
if (err) {
reject(err.message);
} else {
resolve();
}
});
});
});

104
test/queue.ts Normal file
View File

@ -0,0 +1,104 @@
import { performance } from 'perf_hooks';
import test from 'ava';
import { SMTPServer } from 'smtp-server';
import { SMTPClient, Message } from '../email.js';
const port = 7777;
test('queue failures are handled gracefully by client', async (t) => {
const tlsClient = new SMTPClient({ port, timeout: 200, tls: true });
const secureServer = new SMTPServer({ secure: true });
let attemptCount = 0;
let failureCount = 0;
const mailQueue: (() => Promise<void>)[] = [];
function* mailQueueGenerator() {
while (mailQueue.length > 0) {
yield mailQueue.shift();
}
}
await t.throwsAsync(
new Promise<void>((resolve, reject) => {
secureServer
.on('error', () => {
/** intentionally swallow errors */
})
.listen(port, async () => {
const mailTask = async () => {
try {
await tlsClient.sendAsync(
new Message({
from: 'piglet@gmail.com',
to: 'pooh@gmail.com',
subject: 'this is a test TEXT message from emailjs',
text: 'hello friend, i hope this message finds you well.',
})
);
resolve();
} catch (err) {
if (attemptCount < 5) {
void mailQueue.push(mailTask);
} else {
reject(err);
}
throw err;
}
};
void mailQueue.push(mailTask);
for (const task of mailQueueGenerator()) {
const now = performance.now();
const initialAttemptCount = attemptCount++;
try {
t.log(
`Attempting task #${attemptCount}...${
attemptCount > 1
? ` (succeeded: ${
initialAttemptCount - failureCount
} / ${initialAttemptCount})`
: ''
}`
);
await task?.();
t.log(
`Task succeeded (${Math.round(performance.now() - now)}ms).`
);
} catch (err) {
failureCount++;
t.log(
`Task failed: ${err.message} (${Math.round(
performance.now() - now
)}ms)`
);
}
}
t.log(
`Finished after ${attemptCount} attempts (succeeded: ${
attemptCount - failureCount
} / ${attemptCount}).`
);
});
})
);
t.log(
`SMTPClient ${JSON.stringify(
{
// @ts-expect-error need to check protected prop
ready: tlsClient.ready,
// @ts-expect-error need to check protected prop
sending: tlsClient.sending,
state: tlsClient.smtp.state(),
},
null,
'\t'
).replace(/"/g, '')}`
);
// @ts-expect-error need to check protected prop
t.false(tlsClient.ready);
// @ts-expect-error need to check protected prop
t.false(tlsClient.sending);
t.is(tlsClient.smtp.state(), 0);
});

122
yarn.lock
View File

@ -152,14 +152,14 @@
"@types/node" "*"
"@types/nodemailer" "*"
"@typescript-eslint/eslint-plugin@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.21.0.tgz#bfc22e0191e6404ab1192973b3b4ea0461c1e878"
integrity sha512-fTU85q8v5ZLpoZEyn/u1S2qrFOhi33Edo2CZ0+q1gDaWWm0JuPh3bgOyU8lM0edIEYgKLDkPFiZX2MOupgjlyg==
"@typescript-eslint/eslint-plugin@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz#7b52a0de2e664044f28b36419210aea4ab619e2a"
integrity sha512-YCiy5PUzpAeOPGQ7VSGDEY2NeYUV1B0swde2e0HzokRsHBYjSdF6DZ51OuRZxVPHx0032lXGLvOMls91D8FXlg==
dependencies:
"@typescript-eslint/scope-manager" "5.21.0"
"@typescript-eslint/type-utils" "5.21.0"
"@typescript-eslint/utils" "5.21.0"
"@typescript-eslint/scope-manager" "5.22.0"
"@typescript-eslint/type-utils" "5.22.0"
"@typescript-eslint/utils" "5.22.0"
debug "^4.3.2"
functional-red-black-tree "^1.0.1"
ignore "^5.1.8"
@ -167,69 +167,69 @@
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/parser@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.21.0.tgz#6cb72673dbf3e1905b9c432175a3c86cdaf2071f"
integrity sha512-8RUwTO77hstXUr3pZoWZbRQUxXcSXafZ8/5gpnQCfXvgmP9gpNlRGlWzvfbEQ14TLjmtU8eGnONkff8U2ui2Eg==
"@typescript-eslint/parser@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.22.0.tgz#7bedf8784ef0d5d60567c5ba4ce162460e70c178"
integrity sha512-piwC4krUpRDqPaPbFaycN70KCP87+PC5WZmrWs+DlVOxxmF+zI6b6hETv7Quy4s9wbkV16ikMeZgXsvzwI3icQ==
dependencies:
"@typescript-eslint/scope-manager" "5.21.0"
"@typescript-eslint/types" "5.21.0"
"@typescript-eslint/typescript-estree" "5.21.0"
"@typescript-eslint/scope-manager" "5.22.0"
"@typescript-eslint/types" "5.22.0"
"@typescript-eslint/typescript-estree" "5.22.0"
debug "^4.3.2"
"@typescript-eslint/scope-manager@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.21.0.tgz#a4b7ed1618f09f95e3d17d1c0ff7a341dac7862e"
integrity sha512-XTX0g0IhvzcH/e3393SvjRCfYQxgxtYzL3UREteUneo72EFlt7UNoiYnikUtmGVobTbhUDByhJ4xRBNe+34kOQ==
"@typescript-eslint/scope-manager@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.22.0.tgz#590865f244ebe6e46dc3e9cab7976fc2afa8af24"
integrity sha512-yA9G5NJgV5esANJCO0oF15MkBO20mIskbZ8ijfmlKIvQKg0ynVKfHZ15/nhAJN5m8Jn3X5qkwriQCiUntC9AbA==
dependencies:
"@typescript-eslint/types" "5.21.0"
"@typescript-eslint/visitor-keys" "5.21.0"
"@typescript-eslint/types" "5.22.0"
"@typescript-eslint/visitor-keys" "5.22.0"
"@typescript-eslint/type-utils@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.21.0.tgz#ff89668786ad596d904c21b215e5285da1b6262e"
integrity sha512-MxmLZj0tkGlkcZCSE17ORaHl8Th3JQwBzyXL/uvC6sNmu128LsgjTX0NIzy+wdH2J7Pd02GN8FaoudJntFvSOw==
"@typescript-eslint/type-utils@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.22.0.tgz#0c0e93b34210e334fbe1bcb7250c470f4a537c19"
integrity sha512-iqfLZIsZhK2OEJ4cQ01xOq3NaCuG5FQRKyHicA3xhZxMgaxQazLUHbH/B2k9y5i7l3+o+B5ND9Mf1AWETeMISA==
dependencies:
"@typescript-eslint/utils" "5.21.0"
"@typescript-eslint/utils" "5.22.0"
debug "^4.3.2"
tsutils "^3.21.0"
"@typescript-eslint/types@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.21.0.tgz#8cdb9253c0dfce3f2ab655b9d36c03f72e684017"
integrity sha512-XnOOo5Wc2cBlq8Lh5WNvAgHzpjnEzxn4CJBwGkcau7b/tZ556qrWXQz4DJyChYg8JZAD06kczrdgFPpEQZfDsA==
"@typescript-eslint/types@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.22.0.tgz#50a4266e457a5d4c4b87ac31903b28b06b2c3ed0"
integrity sha512-T7owcXW4l0v7NTijmjGWwWf/1JqdlWiBzPqzAWhobxft0SiEvMJB56QXmeCQjrPuM8zEfGUKyPQr/L8+cFUBLw==
"@typescript-eslint/typescript-estree@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.21.0.tgz#9f0c233e28be2540eaed3df050f0d54fb5aa52de"
integrity sha512-Y8Y2T2FNvm08qlcoSMoNchh9y2Uj3QmjtwNMdRQkcFG7Muz//wfJBGBxh8R7HAGQFpgYpdHqUpEoPQk+q9Kjfg==
"@typescript-eslint/typescript-estree@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.22.0.tgz#e2116fd644c3e2fda7f4395158cddd38c0c6df97"
integrity sha512-EyBEQxvNjg80yinGE2xdhpDYm41so/1kOItl0qrjIiJ1kX/L/L8WWGmJg8ni6eG3DwqmOzDqOhe6763bF92nOw==
dependencies:
"@typescript-eslint/types" "5.21.0"
"@typescript-eslint/visitor-keys" "5.21.0"
"@typescript-eslint/types" "5.22.0"
"@typescript-eslint/visitor-keys" "5.22.0"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.21.0.tgz#51d7886a6f0575e23706e5548c7e87bce42d7c18"
integrity sha512-q/emogbND9wry7zxy7VYri+7ydawo2HDZhRZ5k6yggIvXa7PvBbAAZ4PFH/oZLem72ezC4Pr63rJvDK/sTlL8Q==
"@typescript-eslint/utils@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.22.0.tgz#1f2c4897e2cf7e44443c848a13c60407861babd8"
integrity sha512-HodsGb037iobrWSUMS7QH6Hl1kppikjA1ELiJlNSTYf/UdMEwzgj0WIp+lBNb6WZ3zTwb0tEz51j0Wee3iJ3wQ==
dependencies:
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.21.0"
"@typescript-eslint/types" "5.21.0"
"@typescript-eslint/typescript-estree" "5.21.0"
"@typescript-eslint/scope-manager" "5.22.0"
"@typescript-eslint/types" "5.22.0"
"@typescript-eslint/typescript-estree" "5.22.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.21.0":
version "5.21.0"
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz#453fb3662409abaf2f8b1f65d515699c888dd8ae"
integrity sha512-SX8jNN+iHqAF0riZQMkm7e8+POXa/fXw5cxL+gjpyP+FI+JVNhii53EmQgDAfDcBpFekYSlO0fGytMQwRiMQCA==
"@typescript-eslint/visitor-keys@5.22.0":
version "5.22.0"
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.22.0.tgz#f49c0ce406944ffa331a1cfabeed451ea4d0909c"
integrity sha512-DbgTqn2Dv5RFWluG88tn0pP6Ex0ROF+dpDO1TNNZdRtLjUr6bdznjA6f/qNqJLjd2PgguAES2Zgxh/JzwzETDg==
dependencies:
"@typescript-eslint/types" "5.21.0"
"@typescript-eslint/types" "5.22.0"
eslint-visitor-keys "^3.0.0"
acorn-jsx@^5.3.1:
@ -492,9 +492,9 @@ clean-stack@^2.0.0:
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
clean-stack@^4.0.0:
version "4.1.0"
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-4.1.0.tgz#5ce5a2fd19a12aecdce8570daefddb7ac94b6b4e"
integrity sha512-dxXQYI7mfQVcaF12s6sjNFoZ6ZPDQuBBLp3QJ5156k9EvUFClUoZ11fo8HnLQO241DDVntHEug8MOuFO5PSfRg==
version "4.2.0"
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz#c464e4cde4ac789f4e0735c5d75beb49d7b30b31"
integrity sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==
dependencies:
escape-string-regexp "5.0.0"
@ -1084,9 +1084,9 @@ iconv-lite@0.6.3, iconv-lite@^0.6.3:
safer-buffer ">= 2.1.2 < 3.0.0"
ignore-by-default@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.0.0.tgz#537092018540640459569fe7c8c7a408af581146"
integrity sha512-+mQSgMRiFD3L3AOxLYOCxjIq4OnAmo5CIuC+lj5ehCJcPtV++QacEV7FdpzvYxH6DaOySWzQU6RR0lPLy37ckA==
version "2.1.0"
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz#c0e0de1a99b6065bdc93315a6f728867981464db"
integrity sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==
ignore@^5.1.8, ignore@^5.2.0:
version "5.2.0"
@ -1427,10 +1427,10 @@ nearley@^2.20.1:
railroad-diagrams "^1.0.0"
randexp "0.4.6"
nodemailer@6.7.3, nodemailer@6.7.4:
version "6.7.4"
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.4.tgz#28771bda3dda8f2dad1912aca0f8727ce7f09d89"
integrity sha512-TBSS3qS8WG45ycUwEvEA/3UM1o3sLz9jUl4TPUKPz4ImWWM6UgRCb5pLO+HOouDKEj57yNLOrzQlO8+9IjWZoA==
nodemailer@6.7.3, nodemailer@6.7.5:
version "6.7.5"
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz#b30b1566f5fa2249f7bd49ced4c58bec6b25915e"
integrity sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==
nofilter@^3.1.0:
version "3.1.0"
@ -1678,10 +1678,10 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
rollup@2.70.2:
version "2.70.2"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.70.2.tgz#808d206a8851628a065097b7ba2053bd83ba0c0d"
integrity sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==
rollup@2.72.0:
version "2.72.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.72.0.tgz#f94280b003bcf9f2f1f2594059a9db5abced371e"
integrity sha512-KqtR2YcO35/KKijg4nx4STO3569aqCUeGRkKWnJ6r+AvBBrVY9L4pmf4NHVrQr4mTOq6msbohflxr2kpihhaOA==
optionalDependencies:
fsevents "~2.3.2"