Repository navigation
fix(inquiry): swap SendGrid for nodemailer + Gmail SMTP (closes #752) - #753
Merged
Merged
Conversation
The /inquiry route was silently failing in production — verified 2026-05-17 that no recent inquiries were arriving in the destination inbox. Combined with the historical "Maximum credits exceeded" incident captured in docs/inquiry-sendgrid-crash.md, this is the SendGrid free tier hitting its daily cap. Replaces @sendgrid/mail with nodemailer using Gmail SMTP. Rationale: - Volume is well under Gmail SMTP's 500/day cap. - Removes a third-party SaaS billing relationship. - Receiver is already a Gmail account; same-provider auth eliminates the sender-verification dance. Changes: - package.json: -@sendgrid/mail, +nodemailer, +@types/nodemailer. - src/model/inquiry/InquiryController.ts: rewrite using nodemailer with Gmail SMTP. From = process.env.GMAIL_USER. To hardcoded to joshua.v.sherman@gmail.com (decided by Josh 2026-05-17, supersedes the previous web.jam.adm@gmail.com destination from when SendGrid domain-verification permitted any From). Preserves the 502-on-error pattern from PR #748 so unhandled rejections still can't crash the process. - .env.example: -SENDGRID_API_KEY/USERNAME/PASSWORD, +GMAIL_USER, +GMAIL_APP_PASSWORD. - README.md: new "Email (`/inquiry` route)" section documenting the Gmail App Password generation procedure and required env vars. - docs/inquiry-sendgrid-crash.md: update note pointing at this PR as the resolution of the SendGrid-era failure mode. Tests: all 70 existing pass unchanged. The route returns 200 in NODE_ENV=test mode without actually sending, same pattern as before. Resolves #752. Satisfies Phase 3 of #749 (provider swap). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two fixes triggered by CircleCI smoketest failure on PR #753: 1. CI smoketest runs `npm install --omit=dev` then triggers the postinstall TypeScript compile via tsc -p tsconfig.prod.json. With @types/nodemailer in devDependencies, tsc fails with TS7016 because the type declarations aren't installed in --omit=dev mode. Matches the existing convention in this repo: every other @types/* package lives in `dependencies`, not `devDependencies`, for exactly this reason. 2. README "Email" section: add Heroku CLI command examples (heroku config:set / get / unset / logs) AND Heroku dashboard click-by-click so Josh has step-by-step instructions for setting GMAIL_USER and GMAIL_APP_PASSWORD and unsetting the obsolete SENDGRID_* vars in production. Per Josh's 2026-05-17 request. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 19, 2026
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.
Closes #752. Satisfies Phase 3 of #749 (provider swap).
Summary
@sendgrid/mailwithnodemailer+ Gmail SMTP for the/inquiryroute.GMAIL_USER,GMAIL_APP_PASSWORD. Removed:SENDGRID_API_KEY,SENDGRID_USERNAME,SENDGRID_PASSWORD.joshua.v.sherman@gmail.com(per Josh's decision 2026-05-17, supersedesweb.jam.adm@gmail.com).Background
Booking inquiries from joshandmariamusic.com / web-jam.com were silently failing in production. Verified 2026-05-17 that no recent inquiries had arrived at the destination inbox. Combined with the post-mortem in docs/inquiry-sendgrid-crash.md, the most likely cause is the SendGrid free tier hitting its daily 100-email cap (other backend traffic exhausting the quota before form submissions get processed).
Rather than topping up SendGrid or migrating to a different paid provider, this PR drops the SendGrid dependency entirely. Volume is well under Gmail SMTP's 500/day cap, and removing one third-party SaaS billing relationship is a net simplification.
Test plan
npm test)Inquirycomponent, so should pass automatically — verifying anyway per Task 17 clarification)GMAIL_APP_PASSWORDtemporarily and submit; verify the route returns 502 cleanly without crashingRequired follow-up (Josh, after merge)
joshua.v.sherman@gmail.com(Google Account → Security → 2-Step Verification → App Passwords)GMAIL_USER=joshua.v.sherman@gmail.comandGMAIL_APP_PASSWORD=<value>in Heroku config varsSENDGRID_API_KEYfrom Heroku config vars (do this AFTER verifying delivery, so we can roll back if needed)Related
🤖 Generated with Claude Code