@molecule/api-emails-sendmail 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +266 -0
  2. package/package.json +8 -7
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:48:04.838Z
7
+ -->
8
+
9
+ # @molecule/api-emails-sendmail
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ Sendmail email provider for molecule.dev.
16
+
17
+ Uses the local sendmail command to send emails.
18
+
19
+ Note: For this to work, your server must have `sendmail` installed and
20
+ configured. The binary path defaults to `/usr/sbin/sendmail`; set the
21
+ `SENDMAIL_PATH` environment variable to use a different binary (e.g.
22
+ `/usr/lib/sendmail`, or an msmtp/mhsendmail shim in containers). The path
23
+ is read once at module load.
24
+
25
+ ## Type
26
+
27
+ `provider`
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @molecule/api-emails-sendmail @molecule/api-bond @molecule/api-emails nodemailer
33
+ npm install -D @types/nodemailer
34
+ ```
35
+
36
+ ## API
37
+
38
+ ### Interfaces
39
+
40
+ #### `EmailMessage`
41
+
42
+ Email message options.
43
+
44
+ ```typescript
45
+ interface EmailMessage {
46
+ /**
47
+ * Sender address.
48
+ */
49
+ from: string | EmailAddress
50
+ /**
51
+ * Recipient(s).
52
+ */
53
+ to: string | EmailAddress | (string | EmailAddress)[]
54
+ /**
55
+ * CC recipient(s).
56
+ */
57
+ cc?: string | EmailAddress | (string | EmailAddress)[]
58
+ /**
59
+ * BCC recipient(s).
60
+ */
61
+ bcc?: string | EmailAddress | (string | EmailAddress)[]
62
+ /**
63
+ * Reply-to address.
64
+ */
65
+ replyTo?: string | EmailAddress
66
+ /**
67
+ * Email subject.
68
+ */
69
+ subject: string
70
+ /**
71
+ * Plain text body.
72
+ */
73
+ text?: string
74
+ /**
75
+ * HTML body.
76
+ */
77
+ html?: string
78
+ /**
79
+ * File attachments.
80
+ */
81
+ attachments?: EmailAttachment[]
82
+ /**
83
+ * i18n key for the subject (for client-side translation).
84
+ */
85
+ subjectKey?: string
86
+ /**
87
+ * i18n key for the plain text body (for client-side translation).
88
+ */
89
+ textKey?: string
90
+ /**
91
+ * i18n key for the HTML body (for client-side translation).
92
+ */
93
+ htmlKey?: string
94
+ }
95
+ ```
96
+
97
+ #### `EmailSendResult`
98
+
99
+ Result of sending an email.
100
+
101
+ ```typescript
102
+ interface EmailSendResult {
103
+ /**
104
+ * Whether the email was accepted for delivery.
105
+ */
106
+ accepted: string[]
107
+ /**
108
+ * Addresses that were rejected.
109
+ */
110
+ rejected: string[]
111
+ /**
112
+ * Message ID from the provider.
113
+ */
114
+ messageId?: string
115
+ /**
116
+ * Raw response from the provider.
117
+ */
118
+ response?: string
119
+ }
120
+ ```
121
+
122
+ #### `EmailTransport`
123
+
124
+ Email transport interface.
125
+
126
+ All email providers must implement this interface.
127
+
128
+ ```typescript
129
+ interface EmailTransport {
130
+ /**
131
+ * Sends an email message.
132
+ * @returns The send result.
133
+ */
134
+ sendMail(message: EmailMessage): Promise<EmailSendResult>
135
+ }
136
+ ```
137
+
138
+ ### Functions
139
+
140
+ #### `sendMail(message)`
141
+
142
+ Sends an email using the local sendmail binary via nodemailer.
143
+
144
+ ```typescript
145
+ function sendMail(message: EmailMessage): Promise<EmailSendResult>
146
+ ```
147
+
148
+ - `message` — The email message (to, from, subject, text/html, attachments).
149
+
150
+ **Returns:** Send result with accepted/rejected addresses and message ID.
151
+
152
+ ### Constants
153
+
154
+ #### `email` _(deprecated)_
155
+
156
+ Legacy export - the raw nodemailer transport.
157
+
158
+ ```typescript
159
+ const email: nodemailer.Transporter<SentMessageInfo, Options>
160
+ ```
161
+
162
+ #### `nodemailerTransport`
163
+
164
+ The underlying nodemailer transport.
165
+
166
+ The sendmail binary path defaults to `/usr/sbin/sendmail` and can be
167
+ overridden with the `SENDMAIL_PATH` environment variable (e.g.
168
+ `/usr/lib/sendmail`, or an msmtp/mhsendmail shim in containers and tests).
169
+ The path is read once at module load; if the binary is missing, sends fail
170
+ with a `spawn ... ENOENT` error at send time — install sendmail or point
171
+ `SENDMAIL_PATH` at a compatible binary.
172
+
173
+ ```typescript
174
+ const nodemailerTransport: nodemailer.Transporter<SentMessageInfo, Options>
175
+ ```
176
+
177
+ #### `provider`
178
+
179
+ The sendmail email provider implementing the standard interface.
180
+
181
+ ```typescript
182
+ const provider: EmailTransport
183
+ ```
184
+
185
+ #### `transport` _(deprecated)_
186
+
187
+ Legacy export - the raw nodemailer transport.
188
+
189
+ ```typescript
190
+ const transport: nodemailer.Transporter<SentMessageInfo, Options>
191
+ ```
192
+
193
+ ## Core Interface
194
+
195
+ Implements `@molecule/api-emails` interface.
196
+
197
+ ## Bond Wiring
198
+
199
+ Setup function to register this provider with the core interface:
200
+
201
+ ```typescript
202
+ import { setTransport } from '@molecule/api-emails'
203
+ import { provider } from '@molecule/api-emails-sendmail'
204
+
205
+ export function setupEmailsSendmail(): void {
206
+ setTransport(provider)
207
+ }
208
+ ```
209
+
210
+ ## Injection Notes
211
+
212
+ ### Requirements
213
+
214
+ Peer dependencies:
215
+
216
+ - `@molecule/api-bond` ^1.0.1
217
+ - `@molecule/api-emails` ^1.0.1
218
+
219
+ ### Runtime Dependencies
220
+
221
+ - `@molecule/api-bond`
222
+ - `@molecule/api-emails`
223
+ - `nodemailer`
224
+
225
+ On success, `sendMail()` resolves with `accepted` set to the envelope
226
+ recipients (sendmail queues the message for all of them once the binary
227
+ exits 0) and `response: 'Messages queued for delivery'`. Failures reject
228
+ with distinct errors: a missing binary is a `spawn ... ENOENT` error
229
+ (install sendmail or set `SENDMAIL_PATH`), a binary that exits non-zero is
230
+ `Sendmail exited with code <n>`, and an envelope address starting with `-`
231
+ is rejected up front with `Invalid envelope addresses.` (argument-injection
232
+ guard) — inspect the message/`code` to tell configuration problems apart
233
+ from delivery problems.
234
+
235
+ The `accepted`-from-envelope mapping above exists because `@types/nodemailer`
236
+ declares `accepted`/`rejected`/`pending` on `SendmailTransport.SentMessageInfo`
237
+ (and `SESTransport.SentMessageInfo`), but nodemailer's actual sendmail (and
238
+ SES) transports never set them — only the SMTP transports do. Code written
239
+ against the typings type-checks cleanly and reads `undefined`/`[]` at
240
+ runtime. If you upgrade `nodemailer` or `@types/nodemailer`, re-verify this
241
+ against the transport implementations themselves
242
+ (`lib/sendmail-transport/index.js`), not the shipped `.d.ts` — the typings
243
+ are exactly what drifted last time.
244
+
245
+ ## E2E Tests
246
+
247
+ Integration checklist — drive the real UI (live preview, no mocks). The
248
+ sandbox CAPTURES outbound email instead of sending — read each message with
249
+ the `read_activity` tool (filter type 'email'); the verification/reset link
250
+ is in its payload. Never mock the send or modify production code to expose
251
+ it. Adapt each item to this app's actual screens/flows, and check every box
252
+ off one by one. A box you can't check is an integration bug to fix — not a
253
+ skip:
254
+
255
+ - [ ] Each email-triggering flow (signup verification, password-reset request,
256
+ invites/notifications the app defines) confirms the send in the UI ("check
257
+ your inbox") and a message actually reaches the transport.
258
+ - [ ] The password-reset round-trip completes: request a reset → open the
259
+ captured message → follow its single-use link → set a new password → log
260
+ in with it (and the old password no longer works).
261
+ - [ ] The message body contains a LINK, never the raw token/secret, and renders
262
+ with the app's real name/content (no `undefined` placeholders).
263
+ - [ ] Requesting a reset for an unknown email shows the same neutral UI response
264
+ as a known one (no account-existence oracle).
265
+ - [ ] Account emails go only to the account's own address — no UI or endpoint
266
+ lets an unauthenticated caller send to an arbitrary address.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-emails-sendmail",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Sendmail email provider for molecule.dev.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -27,18 +28,18 @@
27
28
  ],
28
29
  "license": "Apache-2.0",
29
30
  "dependencies": {
30
- "nodemailer": "9.0.3"
31
+ "nodemailer": "9.1.1"
31
32
  },
32
33
  "devDependencies": {
33
- "@molecule/api-bond": "1.0.0",
34
+ "@molecule/api-bond": "1.0.1",
34
35
  "@types/node": "26.1.2",
35
36
  "@types/nodemailer": "8.0.1",
36
37
  "typescript": "6.0.3",
37
- "vitest": "4.1.10"
38
+ "vitest": "4.1.11"
38
39
  },
39
40
  "peerDependencies": {
40
- "@molecule/api-bond": "^1.0.0",
41
- "@molecule/api-emails": "^1.0.0"
41
+ "@molecule/api-bond": "^1.0.1",
42
+ "@molecule/api-emails": "^1.0.1"
42
43
  },
43
44
  "repository": {
44
45
  "type": "git",