Skip to content

feat(email): abandoned checkout email, 80% free tier warning, credits exhausted email#3908

Merged
waleedlatif1 merged 13 commits intostagingfrom
abandoned-upgrade-email
Apr 3, 2026
Merged

feat(email): abandoned checkout email, 80% free tier warning, credits exhausted email#3908
waleedlatif1 merged 13 commits intostagingfrom
abandoned-upgrade-email

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented Apr 3, 2026

Summary

  • Handles `checkout.session.expired` Stripe webhook — sends plain personal email from Emir when a user starts an upgrade but doesn't complete it
  • Lowers free tier usage warning email from 90% → 80%
  • Adds structured credits exhausted email when free users hit 100% — "your workflows are paused, upgrade to continue" with Pro features list and upgrade CTA

Type of Change

  • New feature

Testing

Tested manually

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)

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 3, 2026 2:29am

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 3, 2026

PR Summary

Medium Risk
Introduces new Stripe webhook-driven and usage-threshold-driven outbound emails, which can impact customer communications volume and correctness if event/threshold logic misfires. Changes are scoped to notifications email flows and templates, not core billing state transitions.

Overview
Adds two new notification email flows: a plain-text-style personal follow-up when a checkout.session.expired (subscription-mode) Stripe event occurs, and a branded CreditsExhaustedEmail sent when free users cross 100% usage (with upgrade CTA and Pro feature list).

Adjusts free-tier upgrade nudges to trigger at 80% (and updates subject/footer copy), while restricting the existing 80% budget warning email to paid users only. Also centralizes “plain email” styling and Pro feature constants, updates EmailLayout to use the wordmark logo, and reclassifies lifecycle emails to emailType: 'notifications'.

Written by Cursor Bugbot for commit 034b0f9. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 3, 2026

Greptile Summary

This PR adds three email touchpoints for billing lifecycle events: an abandoned checkout recovery email (personal tone, from the founder), a lowered free-tier 80% usage warning (down from 90%), and a new credits-exhausted email when free users hit 100%.

Key changes:

  • checkout.ts — New handleAbandonedCheckout handler wired to checkout.session.expired; correctly guards on session.mode === 'subscription' and isProPlan (covers Pro/Team/Enterprise) so neither payment/setup sessions nor already-subscribed users trigger the email.
  • usage.ts — Restructures the threshold logic: paid users receive the budget-warning email at 80%; free users receive the upgrade nudge at 80% (lowered from 90%), and a new credits-exhausted email at 100%. The three blocks are mutually exclusive and the early-return pattern from the paid-user block cannot skip the free-user 100% block.
  • lifecycle-email.tsemailType changed from 'transactional' to 'notifications'; the onboarding followup email now correctly respects unsubscribeNotifications preferences and receives List-Unsubscribe headers via the mailer's processEmailData path.
  • plainEmailStyles / proFeatures — Shared across onboarding-followup-email, abandoned-checkout-email, and the two billing upgrade emails; eliminates the inline duplication that existed before.
  • wordmark.png — Updated logo asset in EmailLayout with explicit width=107 height=33 dimensions to prevent layout shift in email clients.

Confidence Score: 5/5

Safe to merge — previous P0/P1 concerns have been fully addressed and no new issues were found.

All three prior review threads (subscription-mode filter, existing-subscriber guard, preview-text duplication) are resolved in this commit. The threshold logic in usage.ts is correctly structured: the three email paths (paid 80%, free 80%, free 100%) are mutually exclusive by construction, and the early-return guards cannot interfere with one another. No security, data-loss, or correctness issues remain.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/billing/webhooks/checkout.ts New handler for checkout.session.expired; correctly filters to subscription-mode only and gates on isProPlan (covers Pro, Team, and Enterprise) before sending the abandoned checkout email.
apps/sim/lib/billing/core/usage.ts 80% threshold now correctly splits paid vs free users; 90% free-user block replaced by 100% credits-exhausted block; logic is mutually exclusive and the early-return pattern cannot accidentally skip the 100% block.
apps/sim/components/emails/billing/credits-exhausted-email.tsx New structured email component for free-tier credit exhaustion; uses shared EmailLayout, proFeatures constant, and dollarsToCredits helper — consistent with FreeTierUpgradeEmail patterns.
apps/sim/components/emails/billing/abandoned-checkout-email.tsx Plain personal email component matching the onboarding-followup pattern; shares plainEmailStyles and has a distinct Preview text per the prior review feedback.
apps/sim/background/lifecycle-email.ts Changed emailType from 'transactional' to 'notifications' — the onboarding followup email now correctly respects notification unsubscribe preferences and receives List-Unsubscribe headers.
apps/sim/components/emails/_styles/base.ts Extracted inline plainEmailStyles from onboarding-followup-email into the shared styles module; allows abandoned-checkout-email to reuse the same plain-text look without duplication.
apps/sim/components/emails/billing/constants.ts New shared config file for proFeatures; correctly uses as const and is imported directly by both FreeTierUpgradeEmail and CreditsExhaustedEmail.
apps/sim/lib/auth/auth.ts Wires checkout.session.expired to the new handleAbandonedCheckout handler; minimal change, follows existing webhook dispatch pattern.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Stripe Webhook] --> B{Event Type}

    B -->|checkout.session.expired| C{session.mode === subscription?}
    C -->|No| D[Skip — payment/setup session]
    C -->|Yes| E{User found by stripeCustomerId?}
    E -->|No| F[Log warn & return]
    E -->|Yes| G{isProPlan?}
    G -->|Yes| H[Skip — already subscribed]
    G -->|No| I[Send AbandonedCheckoutEmail\nfrom Emir, emailType: notifications]

    B -->|Usage update| J[maybeSendUsageThresholdEmail]
    J --> K{isFreeUser?}

    K -->|No — Paid user| L{crosses80%?}
    L -->|Yes| M[Send UsageThresholdEmail\nbudget warning]
    L -->|No| N[No email]

    K -->|Yes — Free user| O{crosses100%?}
    O -->|Yes| P[Send CreditsExhaustedEmail\nworkflows paused]
    O -->|No| Q{crosses80%?}
    Q -->|Yes| R[Send FreeTierUpgradeEmail\nupgrade nudge at 80%]
    Q -->|No| S[No email]

    style I fill:#e8f5e9
    style P fill:#ffebee
    style R fill:#fff3e0
    style M fill:#e3f2fd
Loading

Reviews (5): Last reviewed commit: "fix(email): use isProPlan to catch org-l..." | Re-trigger Greptile

@waleedlatif1 waleedlatif1 changed the title feat(email): send plain personal email on abandoned checkout feat(email): abandoned checkout email, 80% free tier warning, credits exhausted email Apr 3, 2026
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

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

@waleedlatif1 waleedlatif1 merged commit ec51f73 into staging Apr 3, 2026
6 checks passed
@waleedlatif1 waleedlatif1 deleted the abandoned-upgrade-email branch April 3, 2026 02:31
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