From 6c9b4aa498eac71752268b4b3f589b470c22d281 Mon Sep 17 00:00:00 2001
From: Jessica Lawshe <5312836+lawshe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 08:05:38 -0500
Subject: [PATCH] Merge pull request #34768 from
overleaf/jel-email-when-domain-verified
[web] Email group admin when domain is verified
GitOrigin-RevId: 5f8bc6187c561067d16863d3586a94ef498f3bdf
---
.../app/src/Features/Email/EmailBuilder.mjs | 29 +++++++++++++++
.../test/unit/src/Email/EmailBuilder.test.mjs | 35 +++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/services/web/app/src/Features/Email/EmailBuilder.mjs b/services/web/app/src/Features/Email/EmailBuilder.mjs
index 2ad9e62b09..33aad13b96 100644
--- a/services/web/app/src/Features/Email/EmailBuilder.mjs
+++ b/services/web/app/src/Features/Email/EmailBuilder.mjs
@@ -1115,6 +1115,35 @@ templates.groupDomainCapturedByGroupChanged = ctaTemplate({
},
})
+templates.domainVerifiedForGroup = NoCTAEmailTemplate({
+ subject(opts) {
+ if (opts.capturedByGroup) {
+ return `Your domain is verified`
+ } else {
+ return 'Your domain is verified — ready to capture?'
+ }
+ },
+ message(opts, isPlainText) {
+ const message = [
+ `We've verified ${_.escape(opts.domain)} for your Overleaf group.`,
+ ]
+
+ if (opts.capturedByGroup) {
+ message.push(`Your group will continue capturing users with this domain.`)
+ } else {
+ message.push(
+ `To complete the capture, reply to this email and we'll take it from there.`,
+ `Once captured, existing Overleaf users with a ${_.escape(opts.domain)} address will be invited to join your group. Until they accept, they won't be able to access Overleaf. New users who sign up with ${_.escape(opts.domain)} will be added to your group automatically.`,
+ `You'll receive a confirmation email once the capture is active.`
+ )
+ }
+
+ return message.map(m => {
+ return EmailMessageHelper.cleanHTML(m, isPlainText)
+ })
+ },
+})
+
function _formatUserNameAndEmail(user, placeholder) {
if (user.first_name && user.last_name) {
const fullName = `${user.first_name} ${user.last_name}`
diff --git a/services/web/test/unit/src/Email/EmailBuilder.test.mjs b/services/web/test/unit/src/Email/EmailBuilder.test.mjs
index 06b61e4243..332a6f3139 100644
--- a/services/web/test/unit/src/Email/EmailBuilder.test.mjs
+++ b/services/web/test/unit/src/Email/EmailBuilder.test.mjs
@@ -1093,6 +1093,41 @@ describe('EmailBuilder', function () {
expect(email.text).to.contain('admin@overleaf.test')
})
})
+
+ describe('domainVerifiedForGroup', function () {
+ it('should build captured-by-group variant', function (ctx) {
+ const email = ctx.EmailBuilder.buildEmail('domainVerifiedForGroup', {
+ to: 'admin@example.com',
+ domain: 'example.com',
+ capturedByGroup: true,
+ })
+
+ expect(email.subject).to.equal('Your domain is verified')
+ expect(email.html).to.contain("We've verified")
+ expect(email.html).to.contain('example.com')
+ expect(email.html).to.contain(
+ 'Your group will continue capturing users with this domain.'
+ )
+ })
+
+ it('should build not-captured variant with support instructions', function (ctx) {
+ const email = ctx.EmailBuilder.buildEmail('domainVerifiedForGroup', {
+ to: 'admin@example.com',
+ domain: 'example.com',
+ capturedByGroup: false,
+ })
+
+ expect(email.subject).to.equal(
+ 'Your domain is verified — ready to capture?'
+ )
+ expect(email.html).to.contain(
+ "To complete the capture, reply to this email and we'll take it from there."
+ )
+ expect(email.html).to.contain(
+ "You'll receive a confirmation email once the capture is active."
+ )
+ })
+ })
})
})
})