Maint/modernize code 2026#5
Merged
Merged
Conversation
- Add Resend and SendGrid as lazily-loaded optional peer dependencies so they add no bloat unless selected via config.service - Introduce normalize.js: a single canonical email shape mapped internally to Mandrill, SMTP/nodemailer, Resend, and SendGrid - Upgrade dependencies to latest, verified on Node.js v24: express 4 -> 5, body-parser 1 -> 2, nodemailer 7 -> 9, morgan 1.11 - Drop direct body-parser dependency in favor of built-in express.json() - Remove unmaintained interval dependency (relied on util.isDate, now undefined on Node 24); inline an equivalent toMilliseconds helper - Add engines node >=18 and bump version 2.0.0 -> 3.0.0
- Rename the provider config key to `provider` (was `smtp`/`api`); cli.js falls back to smtp/api so existing config files keep working - Update config.sample.json to a realistic `provider` example - Restructure readme with Installation and Usage sections covering both the library and CLI strategies, plus per-provider config and install notes - Make the missing optional-SDK error clearer and confirm it fails fast - Add explanatory comments across normalize.js, send.js, and server.js
- Mandrill now reads apiKey (canonical), with accessKeyId kept as a legacy alias, matching the Resend/SendGrid field naming - Add examples/ folder with config.smtp.json, config.mandrill.json, config.resend.json, and config.sendgrid.json - Remove the misleading root config.sample.json (replaced by examples/) - Reference the example files from the readme and note the accessKeyId alias
calvinmetcalf
approved these changes
Jun 18, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Modernizes stillalive for Node.js v24+ and ESM, expands supported email providers (SMTP/Mandrill/Resend/SendGrid), and refreshes docs/examples to match the new configuration and request payload format.
Changes:
- Convert runtime and CLI to ESM (Node v24 engine,
type: module, async factories,express.json()). - Add provider abstraction with optional peer deps (Resend/SendGrid) and introduce a canonical email normalization layer.
- Refresh README and add example provider config files.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| server.js | Migrates server factory to ESM/async, replaces body-parser + interval, adds interval parsing and constant-time key check. |
| send.js | Implements provider-based sender factory (SMTP/Mandrill/Resend/SendGrid) with lazy-loading for optional SDKs. |
| normalize.js | Adds canonical email shape + mappers to provider-native formats. |
| cli.js | Converts CLI to ESM with top-level await and updated config shape (provider with legacy fallbacks). |
| readme.md | Updates usage/config docs for ESM, CLI, new providers, canonical email object, and interval format. |
| package.json | Bumps major version, sets ESM module type/exports, updates deps, adds optional peer deps, sets Node engine to >=24. |
| package-lock.json | Updates lockfileVersion and dependency tree for new versions/engine metadata. |
| .jshintrc | Updates lint config for modules/modern JS settings. |
| examples/config.smtp.json | Adds sample SMTP provider config. |
| examples/config.mandrill.json | Adds sample Mandrill provider config. |
| examples/config.resend.json | Adds sample Resend provider config. |
| examples/config.sendgrid.json | Adds sample SendGrid provider config. |
| config.sample.json | Removes old sample config (legacy shape). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Drop all legacy/back-compat input forms in favor of the canonical shape:
from_email/from_name, snake_case reply_to, the address object key, the
Mandrill accessKeyId alias, and the CLI smtp/api config fallbacks.
Add up-front validation with clear feedback instead of silent failure:
- normalize.js: formatEmail.validate() checks required fields and email
address format, returning human-readable errors.
- server.js: PUT route returns 400 { error, details } for bad payloads;
createServer requires a non-empty string key.
- send.js: createSender throws TypeError for bad config shape, missing
apiKey, or missing SMTP auth.
Robustness fixes:
- server.js: guard non-string key in createEquals (no 500), store timers
in a Map, read req.body defensively.
- cli.js: validate argv with a usage message, resolve path inside try.
- send.js: only blame the optional dep when the error names that module.
Bump .jshintrc esversion to 2022 and document the breaking changes and
new validation responses in the readme (incl. a Migrating to v3 section).
Replace the hand-rolled constant-time byte compare with Node's crypto.timingSafeEqual over fixed-length SHA-256 digests. Hashing both keys to the same length removes the early length-mismatch return, so the check no longer reveals the key's length and never throws on differing lengths. Rename createEquals -> createKeyVerifier and testKey -> verifyKey to make the auth intent clearer.
fetch only rejects on network errors, not HTTP error statuses, so a Mandrill 4xx/5xx (e.g. an invalid key) previously fell through to cb(null, data) and looked like a successful send. Check res.ok and pass an Error with the status and response body to the callback instead.
Contributor
Author
|
Confirmed SMTP and ReSend are working just fine via real-world testing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Forked off of existing PR: #4
inportvariable to listenPortto prevent confusion withimport`.jshintrcto reflect modernization