Skip to content

improvement(email): reply-to help@sim.ai for lifecycle and billing emails#5487

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/reply-to-help-email
Jul 7, 2026
Merged

improvement(email): reply-to help@sim.ai for lifecycle and billing emails#5487
waleedlatif1 merged 2 commits into
stagingfrom
fix/reply-to-help-email

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Onboarding follow-up (5-day), payment-failed, and abandoned-checkout emails now reply-to the shared help inbox (help@sim.ai) instead of a personal email address
  • Added getHelpEmailAddress() in lib/messaging/email/utils.ts and reused it in the help route, removing a duplicated inline expression

Type of Change

  • Improvement

Testing

  • bun run type-check clean on changed files
  • vitest run lib/billing/webhooks/invoices.test.ts passing
  • bunx biome check clean on changed files

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…ails

- onboarding follow-up (5-day), payment-failed, and abandoned-checkout emails now reply-to the shared help inbox instead of a personal address
- added getHelpEmailAddress() and reused it in the help route to remove the duplicated inline expression
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 7, 2026 6:57pm

Request Review

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Narrow email header routing change with no auth or payment logic changes; behavior is covered by an updated invoice webhook test.

Overview
Introduces getHelpEmailAddress() in lib/messaging/email/utils.ts as the single source for the shared help inbox (help@ + email domain), and routes lifecycle, billing, and help-form mail through it for reply-to (and help submissions for to / confirmation reply-to).

Lifecycle and billing notification emails (onboarding follow-up, abandoned checkout, payment failed) still use getPersonalEmailFrom() for the from address but now set reply-to to the help inbox instead of the personal address embedded in PERSONAL_EMAIL_FROM. The help API drops duplicated inline help@… construction in favor of the same helper.

Docs on getPersonalEmailFrom() clarify that lifecycle/billing should not use its replyTo field. A new invoice webhook test asserts payment-failure emails send with replyTo: help@….

Reviewed by Cursor Bugbot for commit de04785. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR routes replies on lifecycle (onboarding follow-up), billing (payment-failed, abandoned-checkout), and help confirmation emails to the shared help@sim.ai inbox instead of a personal address. It also extracts the previously duplicated help@… address expression into a single getHelpEmailAddress() utility.

  • lib/messaging/email/utils.ts: New getHelpEmailAddress() replaces two inline help@${env.EMAIL_DOMAIN || getEmailDomain()} constructions, giving one place to change the address in the future.
  • Three call sites (lifecycle-email.ts, checkout.ts, invoices.ts): destructure only from from getPersonalEmailFrom() and set replyTo from getHelpEmailAddress(), ensuring replies from recipients go to the team inbox.
  • invoices.test.ts: Adds a dedicated test asserting sendEmail receives replyTo: 'help@sim.test', locking in the wiring introduced by this PR.

Confidence Score: 5/5

Safe to merge — the change is additive, isolated to email reply-to wiring, and backed by a new test that verifies the correct address reaches sendEmail.

All three call sites perform a mechanical swap of one well-understood expression for a named utility with identical semantics; no branching logic or auth paths are touched. The new invoices.test.ts case confirms the end-to-end wiring, and the existing test suite remains green.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/messaging/email/utils.ts Adds getHelpEmailAddress() using the same `help@${env.EMAIL_DOMAIN
apps/sim/app/api/help/route.ts Replaces two inline `help@${env.EMAIL_DOMAIN
apps/sim/background/lifecycle-email.ts Switches the onboarding follow-up email reply-to from getPersonalEmailFrom().replyTo (which could be undefined or a personal address) to getHelpEmailAddress().
apps/sim/lib/billing/webhooks/checkout.ts Same reply-to switch as lifecycle-email.ts, applied to the abandoned-checkout email path.
apps/sim/lib/billing/webhooks/invoices.ts Same reply-to switch as lifecycle-email.ts, applied to the payment-failure email path.
apps/sim/lib/billing/webhooks/invoices.test.ts Adds getHelpEmailAddress mock and a new test case asserting sendEmail is called with replyTo: 'help@sim.test' for payment-failure emails, locking in the new behaviour.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Trigger as Trigger (lifecycle / Stripe webhook)
    participant Handler as Email Handler
    participant Utils as email/utils.ts
    participant Mailer as sendEmail()
    participant Recipient as User Inbox

    Trigger->>Handler: event fires
    Handler->>Utils: getPersonalEmailFrom() returns from
    Handler->>Utils: "getHelpEmailAddress() returns help@sim.ai"
    Handler->>Mailer: "sendEmail with from and replyTo help@sim.ai"
    Mailer->>Recipient: delivers email
    Recipient-->>Handler: "user replies routed to help@sim.ai"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Trigger as Trigger (lifecycle / Stripe webhook)
    participant Handler as Email Handler
    participant Utils as email/utils.ts
    participant Mailer as sendEmail()
    participant Recipient as User Inbox

    Trigger->>Handler: event fires
    Handler->>Utils: getPersonalEmailFrom() returns from
    Handler->>Utils: "getHelpEmailAddress() returns help@sim.ai"
    Handler->>Mailer: "sendEmail with from and replyTo help@sim.ai"
    Mailer->>Recipient: delivers email
    Recipient-->>Handler: "user replies routed to help@sim.ai"
Loading

Reviews (2): Last reviewed commit: "fix(email): address Greptile review feed..." | Re-trigger Greptile

Comment thread apps/sim/lib/messaging/email/utils.ts
- add a sendEmail assertion locking in the payment-failure email's replyTo
- clarify getPersonalEmailFrom() JSDoc so it doesn't overstate replyTo's scope
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit de04785. Configure here.

@waleedlatif1 waleedlatif1 merged commit f364614 into staging Jul 7, 2026
13 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/reply-to-help-email branch July 7, 2026 19:01
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.

1 participant