From f0ee57c1e0f40c3b90963daadeca86b0b818ad77 Mon Sep 17 00:00:00 2001 From: Hyu Date: Mon, 24 Aug 2026 14:53:59 +0800 Subject: [PATCH] style(email): use generic LangBot invitation branding (#2466) Co-authored-by: Junyan Qin --- .../pkg/workspace/invitation_delivery.py | 23 +++++----- .../workspace/test_invitation_delivery.py | 43 +++++++++++++++++-- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/langbot/pkg/workspace/invitation_delivery.py b/src/langbot/pkg/workspace/invitation_delivery.py index 75f5f5136..c9f4f888c 100644 --- a/src/langbot/pkg/workspace/invitation_delivery.py +++ b/src/langbot/pkg/workspace/invitation_delivery.py @@ -240,7 +240,7 @@ class InvitationDeliveryService: @staticmethod def _plain_text(workspace_name: str, invitation_link: str) -> str: return ( - 'You have been invited to LangBot Cloud\n\n' + 'You have been invited to join a Workspace in LangBot\n\n' f'Join the Workspace “{workspace_name}” to collaborate with your team.\n\n' f'Accept invitation: {invitation_link}\n\n' 'This secure invitation expires in 7 days and can only be accepted by the email address ' @@ -259,34 +259,31 @@ class InvitationDeliveryService: - Join {escaped_workspace} on LangBot Cloud + Join {escaped_workspace} in LangBot -
You have been invited to join {escaped_workspace} on LangBot Cloud.
+
You have been invited to join {escaped_workspace} in LangBot.
-
- - LangBot - LangBot Cloud - + LangBot + LangBot
+
-
Workspace invitation
+
Workspace invitation

You’re invited to collaborate

-

Join your team on LangBot Cloud and start building together in this Workspace.

+

Join your team in LangBot and start building together in this Workspace.

- +
- diff --git a/tests/unit_tests/workspace/test_invitation_delivery.py b/tests/unit_tests/workspace/test_invitation_delivery.py index 4bfd368d6..91a7136ae 100644 --- a/tests/unit_tests/workspace/test_invitation_delivery.py +++ b/tests/unit_tests/workspace/test_invitation_delivery.py @@ -88,14 +88,15 @@ async def test_environment_mapping_enables_provider_without_leaking_secret(monke assert service.capability() == {'enabled': True, 'provider': 'smtp'} -async def test_cloud_invitation_email_has_branded_html_plain_fallback_and_expiry_copy(): +async def test_invitation_email_has_generic_langbot_brand_plain_fallback_and_expiry_copy(): service = InvitationDeliveryService(_app({})) link = 'https://cloud.langbot.app/invitations/accept#token=lbi_secret&next=' text = service._plain_text('Research & Development', link) html = service._html('Research & Development', link) - assert 'LangBot Cloud' in text + assert 'LangBot' in text + assert 'LangBot Cloud' not in text assert 'Research & Development' in text assert '7 days' in text assert link in text @@ -103,21 +104,55 @@ async def test_cloud_invitation_email_has_branded_html_plain_fallback_and_expiry assert 'Research & Development' in html assert 'expires in 7 days' in html assert 'lbi_secret&next=<unsafe>' in html + assert 'LangBot Cloud' not in html -async def test_cloud_invitation_email_uses_quiet_cloud_lockup_and_compact_fallback_link(): +async def test_invitation_email_uses_quiet_brand_lockup_and_compact_fallback_link(): service = InvitationDeliveryService(_app({})) link = 'https://cloud.langbot.app/invitations/accept#token=lbi_secret' html = service._html("RockChinQ's Workspace", link) assert 'https://docs.langbot.app/langbot-logo.png' in html - assert 'LangBot Cloud' in html + assert '>LangBot<' in html assert 'Workspace invitation' in html assert 'Open invitation link' in html assert 'linear-gradient' not in html assert 'box-shadow' not in html + assert 'border-top:4px solid' not in html + assert 'border:1px solid #dfe6f0' not in html assert 'height="28"' in html assert 'height="32"' in html assert 'margin-top:32px' not in html assert f'>{link}<' not in html + + +async def test_oss_smtp_configuration_delivers_the_generic_invitation_email(): + service = InvitationDeliveryService( + _app( + { + 'workspace': { + 'invitations': { + 'email': { + 'provider': 'smtp', + 'from': 'LangBot ', + 'smtp': {'host': 'smtp.example.com'}, + } + } + } + } + ) + ) + service._send_smtp = AsyncMock(return_value=True) + link = 'https://self-hosted.example/invitations/accept#token=lbi_secret' + + result = await service.deliver_invitation( + recipient_email='member@example.com', + workspace_name='Self-hosted Workspace', + invitation_link=link, + ) + + assert result == InvitationDeliveryResult(status='sent', provider='smtp') + service._send_smtp.assert_awaited_once() + assert 'LangBot Cloud' not in service._plain_text('Self-hosted Workspace', link) + assert 'LangBot Cloud' not in service._html('Self-hosted Workspace', link)
 
Workspace
{escaped_workspace}
@@ -325,7 +322,7 @@ class InvitationDeliveryService:
- Sent by LangBot Cloud
+ Sent by LangBot
If you were not expecting this invitation, you can safely ignore this email.