Skip to content

Commit b634abf

Browse files
andris9claude
andcommitted
docs: add CLAUDE.md with project conventions and release process
Document the project layout, Node 6 engine target, CommonJS/ES2017 conventions, test/lint commands, security practices for SMTP command injection and reply decoding, and the release-please-driven release flow so versioning, CHANGELOG.md, tags, and npm publication are never touched manually. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 95876b1 commit b634abf

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,4 @@ test/dkim/cache/message.*
66
.npmrc
77
examples/test-send.js
88
*.patch
9-
.claude
10-
CLAUDE.md
9+
.claude

CLAUDE.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Nodemailer
2+
3+
E-mail sending library for Node.js. Zero runtime dependencies. Entry point is `lib/nodemailer.js`, which exposes `createTransport(transporter, defaults)` and routes to one of the bundled transports based on the options object.
4+
5+
## Layout
6+
7+
- `lib/nodemailer.js` — public entry, transport dispatch (`createTransport`).
8+
- `lib/mailer/``Mail` class: the user-facing transport wrapper that normalizes messages, runs the DKIM signer, and hands off to the underlying transport's `.send()`.
9+
- `lib/mail-composer/` + `lib/mime-node/` — message → MIME tree → raw RFC822 stream.
10+
- `lib/smtp-connection/` — low-level SMTP/LMTP/ESMTP client. Hot path; security-sensitive. Used by `smtp-transport` and `smtp-pool`.
11+
- `lib/smtp-transport/` — single-shot SMTP transport.
12+
- `lib/smtp-pool/` — pooled SMTP transport with rate limiting.
13+
- `lib/sendmail-transport/`, `lib/ses-transport/`, `lib/stream-transport/`, `lib/json-transport/` — alternate transports.
14+
- `lib/dkim/`, `lib/addressparser/`, `lib/mime-funcs/`, `lib/base64/`, `lib/qp/`, `lib/punycode/`, `lib/well-known/`, `lib/xoauth2/`, `lib/fetch/`, `lib/shared/` — supporting modules.
15+
- `test/` — mirrors `lib/` structure. Most suites spin up real `smtp-server` instances on ephemeral ports; raw `net` servers are used when byte-exact reply control is needed (e.g. injecting non-ASCII or invalid UTF-8).
16+
17+
Each transport must implement `name`, `version`, and `send(mail, callback)`. `Mail` discovers them via duck typing.
18+
19+
## Engine target
20+
21+
`engines.node = ">=6.0.0"`. The library is shipped as ES2017 script-mode CommonJS — no `import`, no top-level `await`, no optional chaining, no nullish coalescing, no class fields. ESLint enforces `ecmaVersion: 2017` and `sourceType: 'script'`. There is a Node 6 syntax-compat check (`npm run test:syntax`, runs `test/syntax-compat.js` inside `node:6-alpine`) that must keep passing — do not introduce syntax that breaks it. `'use strict';` directive at the top of every file.
22+
23+
## Conventions
24+
25+
- CommonJS only: `const x = require('...')`, `module.exports = ...`.
26+
- Callback-first style throughout the public API. Many internals are still callback-based — match the style of the file you are editing rather than introducing promises mid-module.
27+
- Prettier handles formatting; ESLint handles correctness. Run `npm run format` and `npm run lint` before sending changes. The lint config disables Prettier-overlapping rules.
28+
- Snake_case is not used; camelCase for variables and methods, PascalCase for classes.
29+
- Prefer small, surgical diffs. The codebase is mature and load-bearing — avoid drive-by refactors, comment churn, or "improvements" outside the scope of the change.
30+
- Every change to security-sensitive code (anything in `lib/smtp-connection/`, address parsing, header generation, DKIM) needs tests that exercise the failure mode, not just the happy path.
31+
32+
## Testing
33+
34+
- `npm test` — full suite via `node --test` (~150s, 480+ tests, runs serially).
35+
- `npm run test:coverage` — same suite under `c8`.
36+
- `npm run test:syntax` — Node 6 syntax compatibility check in Docker.
37+
- `npm run lint` / `npm run lint:fix`.
38+
- `npm run format` / `npm run format:check`.
39+
40+
Always run `npm test` and `npm run lint` before considering a change done. Tests are required to pass on every commit because release-please cuts releases directly from `master`.
41+
42+
## Releases
43+
44+
Releases, version numbers, the `version` field in `package.json`, git tags, `CHANGELOG.md` entries, and npm publication are all managed automatically by the release-please GitHub Action (`.github/workflows/release.yaml`, configured by `.release-please-config.json`). **Never edit any of these manually and never propose manual edits to them.**
45+
46+
Release-please derives the next version and changelog from Conventional Commit messages on `master`, opens a release PR (`chore: release X.Y.Z [skip-ci]`), and publishes to npm with provenance when that PR is merged. The only thing that should land on `master` between releases is normal commits with Conventional Commit prefixes — release-please takes care of the rest.
47+
48+
Conventional Commit prefixes used in this repo: `fix:`, `feat:`, `chore:`, `docs:`, `refactor:`, `test:`. Use `fix:` for anything users would benefit from seeing in the changelog, including security fixes (reference the GHSA in the body).
49+
50+
## Security
51+
52+
This is a widely-deployed library — security-sensitive changes get extra scrutiny:
53+
- SMTP command injection: any user-controllable value that flows into a written SMTP command (envelope addresses, sizes, the `name`/EHLO option, headers) must be CRLF-stripped or rejected at the boundary. Sanitize at the assignment, not at every call site.
54+
- Server reply parsing in `lib/smtp-connection/index.js` uses a `'binary'` byte-container intermediate to reassemble multi-byte UTF-8 across socket chunks; the actual decode happens at line boundaries via `decodeServerResponse`. Don't change the chunk-buffering encoding without understanding why.
55+
- Reference the GHSA ID in commit messages for advisories.

0 commit comments

Comments
 (0)