Send executive-meeting notification emails for real (SMTP delivery)
Original task #163: replace the no-op outbox-log behaviour in `sendExecutiveMeetingEmail` with real SMTP delivery so approvers actually get pinged in their inbox when an executive-meeting request is awaiting review. Implementation - Added `nodemailer` (and `@types/nodemailer`) as a dependency of `@workspace/api-server`. nodemailer was already in the build's external list, so the bundle stays slim and resolves it at runtime. - Rewrote `sendExecutiveMeetingEmail` in `artifacts/api-server/src/lib/executive-meeting-notify.ts`: - Lazily builds a cached nodemailer transporter from `SMTP_HOST` / `SMTP_PORT` (default 587) / `SMTP_USER` / `SMTP_PASS`, with optional `SMTP_SECURE` and `SMTP_FROM`. Cache is keyed on a config signature, so changing env vars in tests / hot reloads naturally rebuilds the transporter. - When `SMTP_HOST` is unset the previous outbox-style log is kept verbatim as a fallback. Once `SMTP_HOST` is set the fallback branch is no longer reached. - Picks subject/body in the recipient's preferred language (Arabic vs English) with a sensible fallback. - Sends one mail per addressed recipient in parallel; per-recipient failures are caught and logged at warn level. The outer try/catch keeps the function from ever throwing into the transaction caller. SMTP `rejected` arrays are also logged at warn so bounces are visible. Code-review comment follow-ups (applied in this commit) - Transport cache signature now hashes `SMTP_PASS` (sha256, first 16 hex chars) instead of just "***", so rotating to a new password actually rebuilds the cached transporter without leaking plaintext. - Fallback log message now distinguishes "no SMTP_HOST configured" from "SMTP misconfigured" so operators can tell why a delivery was skipped. Verification - Typecheck passes for the modified file (other unrelated pre-existing typecheck failures remain). - `pnpm --filter @workspace/api-server run build` succeeds. - API server boots cleanly with the new dependency. Deviations / scope - No automated tests added; the existing test harness is integration- style and the project already tracks "Add automated tests for the notification fan-out logic" as a separate task. - Persisting per-recipient delivery state into the `executive_meeting_notifications` audit table and a startup `transporter.verify()` were intentionally deferred and proposed as follow-ups (#232 and #233). Replit-Task-Id: 7362e23d-4531-41a8-a6ec-5f48f85b28c9
This commit is contained in:
Generated
+19
@@ -120,6 +120,9 @@ importers:
|
||||
google-auth-library:
|
||||
specifier: ^10.6.2
|
||||
version: 10.6.2
|
||||
nodemailer:
|
||||
specifier: ^8.0.7
|
||||
version: 8.0.7
|
||||
pdfkit:
|
||||
specifier: ^0.18.0
|
||||
version: 0.18.0
|
||||
@@ -160,6 +163,9 @@ importers:
|
||||
'@types/node':
|
||||
specifier: 'catalog:'
|
||||
version: 25.3.5
|
||||
'@types/nodemailer':
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0
|
||||
'@types/pdfkit':
|
||||
specifier: ^0.17.6
|
||||
version: 0.17.6
|
||||
@@ -2657,6 +2663,9 @@ packages:
|
||||
'@types/node@25.3.5':
|
||||
resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==}
|
||||
|
||||
'@types/nodemailer@8.0.0':
|
||||
resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==}
|
||||
|
||||
'@types/pdfkit@0.17.6':
|
||||
resolution: {integrity: sha512-tIwzxk2uWKp0Cq9JIluQXJid77lYhF52EsIOwhsMF4iWLA6YneoBR1xVKYYdAysHuepUB0OX4tdwMiUDdGKmig==}
|
||||
|
||||
@@ -3992,6 +4001,10 @@ packages:
|
||||
node-releases@2.0.36:
|
||||
resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
|
||||
|
||||
nodemailer@8.0.7:
|
||||
resolution: {integrity: sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -6722,6 +6735,10 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 7.18.2
|
||||
|
||||
'@types/nodemailer@8.0.0':
|
||||
dependencies:
|
||||
'@types/node': 25.3.5
|
||||
|
||||
'@types/pdfkit@0.17.6':
|
||||
dependencies:
|
||||
'@types/node': 25.3.5
|
||||
@@ -8044,6 +8061,8 @@ snapshots:
|
||||
|
||||
node-releases@2.0.36: {}
|
||||
|
||||
nodemailer@8.0.7: {}
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
|
||||
Reference in New Issue
Block a user