Skip to content

Redesign share notification email with dual CTAs and org branding settings - #2497

Open
timmilazzo wants to merge 5 commits into
mainfrom
ai_main_ea28b5f9396746b597f5
Open

Redesign share notification email with dual CTAs and org branding settings#2497
timmilazzo wants to merge 5 commits into
mainfrom
ai_main_ea28b5f9396746b597f5

Conversation

@timmilazzo

@timmilazzo timmilazzo commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Reworks the share notification email to lead with who shared the resource, adds a second (dark) CTA and closing paragraphs via a new getShareEmailExtras registration hook, and consolidates organization branding settings (name, logo, brand color, default visibility) into Settings → Organization.

Problem

The primary share-recipient email opened with a generic "You've been given access" heading, included a redundant lead paragraph, and only supported a single CTA with no way to surface a copyable link or closing notes. Additionally, organization branding fields (like the logo used in these emails) were scattered/missing across Settings menus, with no clear place for a user to upload an org logo alongside the organization name.

Solution

Extended the core email template to support a secondary CTA button, closing paragraphs, and reused the existing treated-link block, then introduced a getShareEmailExtras resolver hook on the shareable resource registry so templates (like Clips) can supply resource-specific extras (secondary CTA, link block, closing text) without changing core sharing logic. The share heading was updated to "<sharer> shared "<title>" with you" and the reply-to is already routed to the resource sender. Organization branding UI was consolidated into a single Settings → Organization surface.

Key Changes

  • packages/core/src/server/email-template.ts: Added secondaryCta and closingParagraphs support to renderEmail, including HTML/text rendering for a dark-filled secondary button and closing paragraph block.
  • packages/core/src/sharing/actions/share-resource.ts: Replaced the generic access-granted heading/paragraphs with "<sender> shared "<title>" with you", removed the redundant lead paragraph and footer text, and added support for calling reg.getShareEmailExtras to fetch a ShareEmailExtras payload (secondary CTA, link block, closing paragraphs) with error handling if the resolver fails.
  • templates/clips/server/lib/share-email-hero.ts: Added recordingShareEmailExtras producing the Clips-specific "Summarize with AI" secondary CTA, a copyable agent link block, and closing paragraphs that route replies to the sender.
  • templates/clips/server/db/index.ts: Wired getShareEmailExtras into the recording's registerShareableResource config.
  • templates/clips/shared/clips-ai-prefs.ts: Removed the unused displayName field from ClipsUserPrefs.
  • Added a changeset and two Clips changelog entries documenting the share email update and the organization settings consolidation.
  • Added test coverage in email-template.spec.ts for the secondary CTA and closing paragraphs rendering in both HTML and plain text.

Edit in Builder  Preview


To clone this PR locally use the Github CLI with command gh pr checkout 2497

You can tag me at @BuilderIO for anything you want me to fix or change

@netlify

This comment has been minimized.

@builder-io-integration builder-io-integration Bot changed the title Update from the Builder.io agent Redesign share notification email with dual CTAs and org branding settings Jul 29, 2026
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@builder-io-integration builder-io-integration Bot 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.

Builder reviewed your changes and found 2 potential issues 🟡

Review Details

Code Review Summary

PR #2497 redesigns Clips share-notification emails with sender-specific headings, a secondary CTA, treated link blocks, and closing copy through a new getShareEmailExtras registration hook. It also consolidates organization identity and branding into the Organization settings tab, removes the General profile card, adds branding previews, and updates navigation to the new hash-based tab.

The overall approach is sound: the email renderer preserves existing escaped inline-markup conventions, the new hook is optional and failure-isolated, and the settings component distinguishes loading/error/empty states rather than silently treating a failed request as missing branding. Core email-template coverage was expanded for both HTML and plain text.

Key Findings

  • 🟡 MEDIUM — The removed /settings/organization route has no backward-compatible redirect, so existing bookmarks or external links can produce a 404 after the settings relocation.
  • 🟡 MEDIUM — The Clips “copyable agent link” in the email is built from the normal recording URL. For private/org recordings, that URL requires browser authentication and is not the documented short-lived agent_access URL intended for external agents.

Risk assessment: Standard, because this combines shared email behavior and user-facing settings/navigation changes.

🧪 Browser testing: Attempted FULL verification, but all 16 planned cases could not be verified because the browser executor lacked Chrome automation tools; the dev server itself was healthy.

}[];
}

export default function OrganizationSettingsRoute() {

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.

🟡 Preserve a redirect for the removed organization settings route

Removing this route leaves the previously exposed /settings/organization URL without a matching route. Existing bookmarks, shared links, and cached navigation can now land on a 404 instead of the relocated Organization tab; keep a lightweight redirect to /settings#organization (or an equivalent route-level migration).

Additional Info
Found by 2 of 4 code-review agents; browser test TC-08 could not verify live behavior because Chrome automation was unavailable.

Fix in Builder

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.

this is okay, I doubt anyone used this branding as I found some bugs yesterday. We can add it later

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.

Skipping per @shomix — the branding route was new and effectively unused, so we can add a redirect later if anyone reports a dead bookmark.

Comment on lines +70 to +72
linkBlock: {
intro: "Copy and paste this link for your own AI agent to summarize:",
url: ctx.href,

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.

🟡 Generate a scoped agent URL for the copyable link

The new “Copy and paste this link for your own AI agent” block uses ctx.href, which is the normal recording URL. For private or organization-only recordings, that URL requires the recipient’s authenticated browser session, so an external agent cannot fetch the clip context; use the existing short-lived agent_access link mechanism for this block instead.

Additional Info
Found by 1 of 4 code-review agents; the Clips instructions document create-recording-agent-link as the two-hour agent_access URL, and browser TC-15 could not be exercised because Chrome automation was unavailable.

Fix in Builder

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.

Leaving the plain clip URL here. The scoped agent_access link is a two-hour token, and share emails are routinely opened hours or days later — a copyable link that is already dead by the time the recipient pastes it is worse than one that asks them to sign in. The recipient also just received a share grant, so the normal URL works for them; the block is aimed at pasting into their own agent, which for public clips works today. Happy to revisit if we add a longer-lived, revocable agent link.

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

Nice, left some comments, but all in all looks good, will let builder address them.

const { session } = useSession();
const t = useT();
const agentSettingsTabs = useAgentSettingsTabs();
// Organization identity (name, logo, brand color) belongs with membership,

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.

Nice!!

brandLogoUrl,
preheader: subject,
heading: "You've been given access",
paragraphs: [

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.

removing this paragraphs will remove it from all the other templates. Lets keep them and make them configurable. So that if a caller passes an option, they can override them

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.

Done — the default two paragraphs are back for every template, and a registration can now override them. ShareEmailExtras gained an optional paragraphs field: omit it to keep the default copy, or pass [] to send none. Clips passes [] so its heading sits directly above the thumbnail; nothing else changes.

@shomix

shomix commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@builderio-bot take a look at the comments on this PR and address them if they are valid and would improve the changes

@builder-io-integration

Copy link
Copy Markdown
Contributor

Addressed the PR feedback:

  • @shomix on share-resource.ts (valid, fixed): the two default body paragraphs are back for every template. ShareEmailExtras gained an optional paragraphs field — omit to keep the default copy, pass [] to send none. Clips passes [] so its heading sits directly above the thumbnail; the footer went back to its original wording since the sign-in hint lives in the default paragraph again.
  • Bot: redirect for /settings/organization — skipped, per @shomix's reply that the branding route was effectively unused.
  • Bot: use a scoped agent_access URL in the copyable link — declined with reasoning: that token lasts two hours, and share emails are commonly opened days later, so the pasted link would already be dead. Replied on the thread.

Core rebuilt, email-template + sharing tests pass (41), clips typechecks, files formatted, changeset updated.



🟢 PR feedback addressed: paragraphs made overridable, two bot suggestions answered on-thread.

@github-actions

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

@builder-io-integration builder-io-integration Bot 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.

Builder reviewed your changes and found 1 potential issue 🟡

Review Details

Incremental Code Review Summary

The latest commit adds ShareEmailExtras.paragraphs, allowing a resource-specific hook to intentionally replace the default share-email body with either custom paragraphs or an empty array. The ?? fallback correctly preserves the default body for resources that omit the field while allowing Clips to suppress redundant copy. Existing open findings about the removed /settings/organization route and the non-scoped agent link remain unresolved and are intentionally not reposted.

The new hook remains optional and resolver failures are isolated, and the existing email-template behavior and Clips closing-copy escaping are otherwise consistent with the current trusted-markup conventions. However, the new generic paragraph surface broadens the raw-HTML boundary without making that contract explicit or enforcing it.

New Finding

  • 🟡 MEDIUMShareEmailExtras.paragraphs is passed directly to the email renderer, which inserts paragraphs verbatim. A future resource hook that treats this new field as ordinary text and includes a user-controlled title or description could inject HTML into share emails. The contract should either escape ordinary paragraph text centrally and provide a typed trusted-markup helper, or explicitly document/enforce that this field accepts only treated markup.

Risk assessment: Standard.

🧪 Browser testing: Full verification was attempted, but all 15 planned cases were blocked because Chrome executor tools were unavailable; the dev server was healthy and route/action checks were performed non-visually.

Comment thread packages/core/src/sharing/actions/share-resource.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants