Add Transactional Email Sending
Integrate real transactional email capability into the existing app using SendGrid (or similar) with persistent templates and an API endpoint.
The route
6 steps to Done
- 01
Configure Email Service Credentials
Provide the app with real SendGrid (or chosen provider) credentials and install the SDK.
Preview prompt + verify gate ▾ Hide ▴
1. Open the project's .env file and add two new lines: SENDGRID_API_KEY=your_real_sendgrid_key and FROM_EMAIL=verified_sender@example.com. 2. Run npm install @sendgrid/mail and verify it appears in package.json. 3. In the config directory (e.g., src/config/index.js), import process.env and export an object containing sendgridKey and fromEmail. 4. Ensure the config file is required wherever environment variables are used. 5. Do NOT add placeholder strings; the key must be a non‑empty string and the email must match a verified SendGrid sender. Provide a diff for each changed file and a short explanation of the changes.
- ✓ Does .env contain SENDGRID_API_KEY with a non‑empty value?
- ✓ Is @sendgrid/mail listed in package.json dependencies?
- ✓ Does src/config/index.js export sendgridKey and fromEmail from process.env?
- 02
Create Persistent Email Template Storage
Store reusable email templates in the database so they can be selected at runtime.
Preview prompt + verify gate ▾ Hide ▴
1. Generate a migration that creates a table called email_templates with columns: id (primary key, UUID or auto‑increment), name (string, unique, not null), subject (string, not null), body (text, not null). 2. Apply the migration. 3. Create or update the ORM model (e.g., src/models/EmailTemplate.js or Prisma schema) to match the table, including validation that name is unique. 4. Export the model for use elsewhere. 5. Do NOT add dummy template rows; the table must be empty after migration. Provide the migration file content, the model file, and a short note on how to run migrations.
- ✓ Is there a migration file that creates email_templates with id, name, subject, body?
- ✓ Has the migration been applied and the table exists?
- ✓ Does the ORM model match the table schema and export correctly?
- 03
Implement Transactional Email Service
Create a reusable function that loads a template, interpolates data, and sends the email via SendGrid.
Preview prompt + verify gate ▾ Hide ▴
1. Create src/services/emailService.js. 2. Import @sendgrid/mail, the config module, and the EmailTemplate ORM model. 3. Initialize SendGrid with the API key from config. 4. Export an async function sendTransactional(to, templateName, data) that: a) Queries EmailTemplate where name = templateName; throws an error if not found. b) Performs a simple replacement: for each key in data, replace all occurrences of {{key}} in subject and body. c) Calls sgMail.send({ to, from: config.fromEmail, subject, html: body }). d) Returns the SendGrid response. 5. Include proper error handling (try/catch) and propagate errors. 6. Do NOT mock sgMail; use the real SDK. Provide the full file content.
- ✓ Does emailService.js export sendTransactional?
- ✓ Does the function query EmailTemplate and replace {{placeholders}}?
- ✓ Is sgMail.send called with real parameters and not a mock?
- 04
Add API Endpoint for Transactional Emails
Expose a POST /api/email/transactional route that callers can use to trigger emails.
Preview prompt + verify gate ▾ Hide ▴
1. In the routes folder (e.g., src/routes/email.js), add a new router.post('/transactional', authMiddleware, async (req, res) => { ... }). 2. Validate req.body contains: to (string, email format), templateName (string), data (object). If validation fails, respond 400 with error details. 3. Call await sendTransactional(to, templateName, data). 4. On success, respond with { success: true, messageId: response[0].headers['x-message-id'] } (or similar SendGrid identifier). 5. Catch errors, log, and respond 500 with { success: false, error: error.message }. 6. Register the new router in the main app (e.g., app.use('/api/email', emailRouter)). 7. Do NOT return placeholder IDs; use the actual SendGrid response. Provide the full route file and the line added to app.js.
- ✓ Is the route file present and registered in the main app?
- ✓ Does it validate the payload and return 400 on errors?
- ✓ Does a successful request return 200 and include a real messageId?
- 05
Create a Sample Email Template for Testing
Provide a concrete template to use in manual tests of the new endpoint.
Preview prompt + verify gate ▾ Hide ▴
Create a new file src/seeds/createWelcomeTemplate.js that, when run with `node src/seeds/createWelcomeTemplate.js`, performs: 1) Imports the ORM and EmailTemplate model. 2) Calls EmailTemplate.create({ name: 'welcome', subject: 'Welcome, {{username}}!', body: '<p>Hello {{username}}, thanks for joining.</p>' }). 3) Logs success or error and exits. 4) Ensure the script does not create duplicate entries (check if a template with that name exists first). Provide the full script content and the exact command to run it.
- ✓ Does src/seeds/createWelcomeTemplate.js exist?
- ✓ When run, does it create the template only if it doesn't exist?
- ✓ Does the DB contain the 'welcome' template with correct subject and body?
- 06
Verify End‑to‑End Email Delivery
Ensure the full stack (template, service, endpoint) sends a real email to a test address.
Preview prompt + verify gate ▾ Hide ▴
Execute the following steps: 1) Ensure the server is running locally (e.g., `npm start`). 2) Use curl to POST JSON to http://localhost:3000/api/email/transactional: { "to": "your_test_email@example.com", "templateName": "welcome", "data": { "username": "TestUser" } } Include appropriate headers: Content-Type: application/json and Authorization if required. 3) Capture the response; it should be 200 with a messageId. 4) Check your test inbox for an email with subject "Welcome, TestUser!" and body containing "Hello TestUser". 5) Document the response JSON and screenshot or note of the received email. Provide the exact curl command and a checklist of what to verify.
- ✓ Did curl return HTTP 200?
- ✓ Does the response JSON contain a non‑empty messageId?
- ✓ Is the email received with correct subject and body?