Skip to content

[PM-40167] feat: Update billing domain email copy - #8203

Open
cyprain-okeke wants to merge 5 commits into
mainfrom
billing/pm-40167/server-emails-billing-domain-license-subscription-seats-sponsorship-billing
Open

[PM-40167] feat: Update billing domain email copy#8203
cyprain-okeke wants to merge 5 commits into
mainfrom
billing/pm-40167/server-emails-billing-domain-license-subscription-seats-sponsorship-billing

Conversation

@cyprain-okeke

@cyprain-okeke cyprain-okeke commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-40167
https://bitwarden.atlassian.net/browse/PM-42261
https://bitwarden.atlassian.net/browse/PM-42262
https://bitwarden.atlassian.net/browse/PM-42264

📔 Objective

Refreshes subject lines and body copy for nine billing-domain emails (HTML + text variants) per the PM-38898 terminology epic:

  • LicenseExpired — subject only ("License expired")
  • OrganizationSeatsMaxReached / OrganizationSmSeatsMaxReached / OrganizationSmServiceAccountsMaxReached — lowercased subjects; body now leads with the organization name (added OrganizationName to the view models via CoreHelpers.SanitizeForEmail)
  • Provider/ProviderUpdatePaymentMethod — "Your Bitwarden organization…" copy and Admin Console navigation wording
  • FamiliesForEnterprise offer (new + existing account), sponsorship reverting, and removed-from-family emails — "Sponsored Families Plan" terminology, updated subjects and body copy

Additional changes riding along:

  • Removed the now-unused offerAcceptanceDate parameter from SendFamiliesForEnterpriseRemoveSponsorshipsEmailAsync (interface, both implementations, caller, tests)
  • Sponsor org name in offer emails now passes through CoreHelpers.SanitizeForEmail, matching the sibling sponsorship-removal email
  • Fixed the sponsorship-reverting text template referencing a nonexistent {{Date}} property (previously rendered a blank date); both variants now use {{date ExpirationDate 'MMMM dd, yyyy'}}
  • Unit tests added for all changed emails, rendering the real embedded templates and asserting subjects, body copy (HTML + text), retained CTA links/disclaimers, and date formatting

Notes for reviewers:

  • The ticket description still says the copy is gated behind the vfo1-foundation flag as duplicate V2 templates — that's stale. Nick Krantz confirmed the copy ships in-place with no flag; the ticket AC predates that decision.
  • The removed-sponsorship email keeps the "Or click the following link: {subscription URL}" line per the ticket's copy spec. In the HTML variant this renders the raw URL as visible link text (previously anchored behind "Subscription page") and the "Or" no longer has an antecedent — flagged to product as a copy-deck question rather than deviating from the specified copy here.

Refreshes subject lines and body copy for nine billing emails
(license, seat limits, provider payment method, and Families for
Enterprise sponsorship) per the PM-38898 terminology epic. Copy
ships in-place with no feature flag per product decision.

Also removes the unused offerAcceptanceDate parameter from
SendFamiliesForEnterpriseRemoveSponsorshipsEmailAsync, sanitizes
the sponsor org name in offer emails, and fixes the sponsorship
reverting text template referencing a nonexistent {{Date}} property.
@cyprain-okeke cyprain-okeke added the ai-review Request a Claude code review label Aug 13, 2026
@github-actions github-actions Bot added the platform-community Touches a Platform-stewarded area with limited team familiarity label Aug 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

ℹ️ Limited Platform familiarity

This PR touches a platform-community area. The Platform team owns this code but does not actively develop it, so a Platform review here may be less authoritative than usual.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Re-reviewed after the [PM-42261] fix: Address QA defects on billing domain emails commit, on top of the previously reviewed copy updates across nine billing-domain email templates (HTML + text), the OrganizationName view model additions, the subject line changes in HandlebarsMailService, and the removal of the offerAcceptanceDate parameter from SendFamiliesForEnterpriseRemoveSponsorshipsEmailAsync. Verified the four QA fixes: dropping CoreHelpers.SanitizeForEmail from the seat/machine-account and sponsorship-offer names is safe because all three sites render through escaping double-stashes and the recipients are the organization's own owners (the sponsorship-offer call site is unchanged relative to main); switching the offer text templates and ProviderUpdatePaymentMethod.text.hbs to triple-stash removes HTML-encoded ampersands and a stray <a> tag from plain-text bodies, while the HTML template correctly retains the link helper; and OrganizationServiceAccountsMaxReachedViewModel now inheriting BaseMailModel supplies the CurrentYear the FullHtmlLayout footer needs (neither WebVaultUrl nor SiteName is referenced by that layout). Also confirmed {{date ExpirationDate 'MMMM dd, yyyy'}} matches the registered helper signature and existing template usage, all three OrganizationSeatsMaxReached*/ServiceAccounts* construction sites populate OrganizationName, the interface change is propagated to both IMailService implementations and the sole caller, and no stale references to OfferAcceptanceDate, {{Date}}, or the old subject strings remain in src/, test/, or bitwarden_license/.

Code Review Details

No findings at or above the reporting threshold.

Notes considered and intentionally not raised as findings:

  • The dangling "Or click the following link:" line in FamiliesForEnterpriseRemovedFromFamilyUser (both variants) is already documented in the PR description as an open copy-deck question with product.
  • {{OrganizationName}} in the .text.hbs variants is HTML-escaped by Handlebars, so an org name containing & renders as &amp; in the plain-text body. This matches the existing convention across ~15 other text templates (AdminResetPassword, LicenseExpired, OrganizationUserAccepted, etc.) and is not introduced by this PR.
  • The /billing/payment-method/billing/payment-details route change and the help-article anchor change cannot be verified from this repository; both are explicitly part of the QA-defect fix (PM-42262) and are assumed validated against the web client.

…n-license-subscription-seats-sponsorship-billing
@cyprain-okeke cyprain-okeke added the t:feature Change Type - Feature Development label Aug 13, 2026
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.40%. Comparing base (ac309aa) to head (9782ff5).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8203      +/-   ##
==========================================
+ Coverage   63.29%   63.40%   +0.10%     
==========================================
  Files        2401     2401              
  Lines      104043   104045       +2     
  Branches     9426     9426              
==========================================
+ Hits        65857    65971     +114     
+ Misses      35930    35815     -115     
- Partials     2256     2259       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cyprain-okeke
cyprain-okeke marked this pull request as ready for review August 14, 2026 07:54
@cyprain-okeke
cyprain-okeke requested review from a team as code owners August 14, 2026 07:54
…n-license-subscription-seats-sponsorship-billing
djsmith85
djsmith85 previously approved these changes Aug 14, 2026

@djsmith85 djsmith85 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.

Approving for platform

@djsmith85
djsmith85 removed the request for review from dani-garcia August 14, 2026 08:00
sven-bitwarden
sven-bitwarden previously approved these changes Aug 14, 2026
…er-emails-billing-domain-license-subscription-seats-sponsorship-billing

# Conflicts:
#	src/Core/MailTemplates/Handlebars/FamiliesForEnterprise/FamiliesForEnterpriseOfferExistingAccount.html.hbs
#	src/Core/MailTemplates/Handlebars/FamiliesForEnterprise/FamiliesForEnterpriseOfferExistingAccount.text.hbs
#	src/Core/MailTemplates/Handlebars/FamiliesForEnterprise/FamiliesForEnterpriseOfferNewAccount.html.hbs
#	src/Core/MailTemplates/Handlebars/FamiliesForEnterprise/FamiliesForEnterpriseOfferNewAccount.text.hbs
- PM-42261: render organization names verbatim in the seat limit,
  Secrets Manager limit, and sponsorship offer email bodies instead of
  applying [dot]/[at] substitution, matching the subject line
- PM-42262: point the provider payment method email at the
  billing/payment-details route, update the help article anchor, and
  render plain text links as bare URLs instead of HTML anchors or
  HTML-encoded ampersands
- PM-42264: inherit BaseMailModel so the Secrets Manager machine
  accounts limit email footer renders the copyright year

Also aligns sponsorship offer email test expectations with the
PM-41951 copy that shipped on main and won the merge conflict.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review platform-community Touches a Platform-stewarded area with limited team familiarity t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants