Skip to content

Implement email receipt delivery via SendGrid#146

Merged
kilodesodiq-arch merged 1 commit into
ChainForgee:mainfrom
noevidence1017:fix/email-receipt-delivery
Jun 22, 2026
Merged

Implement email receipt delivery via SendGrid#146
kilodesodiq-arch merged 1 commit into
ChainForgee:mainfrom
noevidence1017:fix/email-receipt-delivery

Conversation

@noevidence1017

Copy link
Copy Markdown
Contributor

I implemented real email delivery for claim receipts, resolving issue #94, on branch fix/email-receipt-delivery.

What changed:

app/backend/src/notifications/email/email.service.ts (new) — wraps the SendGrid SDK, reads SENDGRID_API_KEY/EMAIL_FROM_ADDRESS/EMAIL_FROM_NAME from env, throws on failure (no swallowing) so the BullMQ processor's existing retry/backoff/DLQ logic kicks in, and records Prometheus metrics for every attempt.
app/backend/src/notifications/email/email.service.spec.ts (new) — unit tests for configured/unconfigured/success/failure paths.
app/backend/src/notifications/notifications.processor.ts — replaced the mock email branch with a real call to EmailService.sendEmail; SMS remains mocked (out of scope for #94).
app/backend/src/notifications/notifications.module.ts — registers EmailService.
app/backend/src/observability/metrics/metrics.providers.ts + metrics.service.ts — added email_delivery_total counter and email_delivery_duration_seconds histogram, plus a recordEmailDelivery helper that also feeds the existing error-rate counter.
app/backend/src/claims/claims.service.ts — sendReceiptViaEmail now calls NotificationsService.sendEmail (existing BullMQ-backed outbox path) per recipient instead of just logging a stub; logs only counts/claim IDs, never addresses or receipt text.
app/backend/src/claims/claims.module.ts — imports NotificationsModule so ClaimsService can inject NotificationsService.
app/backend/package.json — added @sendgrid/mail dependency.
app/backend/.env.example — added SENDGRID_API_KEY, EMAIL_FROM_ADDRESS, EMAIL_FROM_NAME.
Updated claims.service.spec.ts and notifications.processor.spec.ts to provide/mock the new dependencies so existing DI wiring keeps compiling.
Note: I could not run npm install/jest in this sandbox — the project requires Node ≥18.18 for Prisma and the environment has Node 18.16.1, plus an unrelated npm cache permission issue. This is a pre-existing environment limitation, not something introduced by this change. I'd recommend running the test suite in CI/your local environment before merging.

Git commands:

git add app/backend/package.json app/backend/.env.example app/backend/src/claims/claims.module.ts app/backend/src/claims/claims.service.ts app/backend/src/claims/claims.service.spec.ts app/backend/src/notifications/notifications.module.ts app/backend/src/notifications/notifications.processor.ts app/backend/src/notifications/notifications.processor.spec.ts app/backend/src/notifications/email/ app/backend/src/observability/metrics/metrics.providers.ts app/backend/src/observability/metrics/metrics.service.ts
git commit -m "feat(backend): implement email receipt delivery via SendGrid"
Suggested PR description:

Title: Implement email receipt delivery via SendGrid

Summary

sendReceiptViaEmail in claims.service.ts was a logging-only stub — claim receipts requested via email were never actually delivered. This wires the existing BullMQ notifications infrastructure to a real SendGrid-backed EmailService.

Added EmailService (notifications/email/email.service.ts) wrapping the SendGrid SDK, configured via SENDGRID_API_KEY, EMAIL_FROM_ADDRESS, EMAIL_FROM_NAME env vars.
NotificationProcessor now calls EmailService.sendEmail for queued email jobs instead of mocking the send; failures propagate so the existing BullMQ attempts: 3 exponential backoff and DLQ handling apply unchanged.
ClaimsService.sendReceiptViaEmail now enqueues through NotificationsService.sendEmail (existing outbox-backed queue) rather than logging a stub message.
Added email_delivery_total counter and email_delivery_duration_seconds histogram to the metrics module, feeding the existing error-rate counter on failure.
Logging only includes claim IDs and recipient counts — never email addresses or receipt content.
Closes #94

Test plan

npm test in app/backend (added email.service.spec.ts, updated notifications.processor.spec.ts and claims.service.spec.ts for the new DI wiring)
Set SENDGRID_API_KEY in a dev environment and confirm a real receipt email is delivered end-to-end
Confirm /metrics exposes email_delivery_total and email_delivery_duration_seconds
Confirm a forced SendGrid failure retries per the existing backoff and lands in the DLQ/outbox failed status after exhausting attempts

@kilodesodiq-arch kilodesodiq-arch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @noevidence1017 — SendGrid wiring plus the new delivery metrics are well done and the provider+processor+service specs are thorough. One follow-up (not blocking): make sure the service falls back gracefully when SENDGRID_API_KEY is unset rather than throwing on init. We can tighten that in a separate PR. Merging for now.

Copy link
Copy Markdown
Contributor

Heads up @noevidence1017#139 (Twilio SMS) merged first and touched claims.module.ts and claims.service.spec.ts, which this PR also changes. The merge now has conflicts.

The approval still stands conceptually — please rebase onto current main and I will merge right after. If the conflict is non-trivial (semantic, not just add/remove), ping me and we will diff together.

@noevidence1017 noevidence1017 force-pushed the fix/email-receipt-delivery branch from d29deb6 to 0b1c762 Compare June 21, 2026 14:07
@noevidence1017

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (includes #139 Twilio SMS). The conflicts were semantic, not pure add/remove, so a quick summary of how I resolved them:

  • notifications.module.ts / notifications.processor.ts — kept both providers. SMS now routes through smsProvider (Twilio/feat(backend): deliver SMS claim receipts via Twilio #139) and email through EmailService (this PR). Since NotificationType only has SMS and EMAIL, both are now handled by real providers, so the old mock fallthrough became dead code (never) — I replaced it with an exhaustiveness guard that throws on an unhandled type rather than silently mock-succeeding.
  • notifications.processor.spec.ts / claims.service.spec.ts — merged both mock sets (smsProvider/EmailService, sendSms/sendEmail) and kept both test groups; added a cross-check that EmailService isn't called for SMS jobs.
  • .env.example — kept both the Twilio and SendGrid blocks.

Verified locally: tsc --noEmit clean, eslint clean on the touched files, and the notifications/email/claims suites pass (34 tests). Did not touch pnpm-lock.yaml — CI installs with --no-frozen-lockfile and resolves @sendgrid/mail from package.json. Ready for merge.

Copy link
Copy Markdown
Contributor

Thanks @noevidence1017 — clean SendGrid integration with metrics and error handling in place. Backend CI is green and #94 is fully resolved. Merging now.

@kilodesodiq-arch kilodesodiq-arch merged commit 8001eae into ChainForgee:main Jun 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HIGH] Implement email notification service integration (SendGrid or AWS SES)

2 participants