diff --git a/services/web/app/src/Features/Email/EmailBuilder.js b/services/web/app/src/Features/Email/EmailBuilder.js
index dbee3c7005..b3dc813c51 100644
--- a/services/web/app/src/Features/Email/EmailBuilder.js
+++ b/services/web/app/src/Features/Email/EmailBuilder.js
@@ -437,6 +437,64 @@ templates.inviteNewUserToJoinManagedUsers = ctaTemplate({
},
})
+templates.surrenderAccountForManagedUsers = ctaTemplate({
+ subject(opts) {
+ const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin'))
+
+ const toGroupName = opts.groupName ? ` to ${opts.groupName}` : ''
+
+ return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}`
+ },
+ title(opts) {
+ const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin'))
+
+ const toGroupName = opts.groupName ? ` to ${opts.groupName}` : ''
+
+ return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}`
+ },
+ message(opts, isPlainText) {
+ const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin'))
+
+ const groupName = opts.groupName ?? `a group managed by ${admin}`
+
+ // TODO update with actual wiki link once created
+ const managedUsersLink = EmailMessageHelper.displayLink(
+ 'user account management',
+ `${settings.siteUrl}/learn/how-to/Managed_Users`,
+ isPlainText
+ )
+
+ return [
+ `Your ${settings.appName} account ${_.escape(
+ opts.to
+ )} is part of ${groupName} and your group administrator has now enabled ${managedUsersLink}. This will ensure that projects aren’t lost when someone leaves the group.`,
+ ]
+ },
+ secondaryMessage(opts, isPlainText) {
+ const transferProjectOwnershipLink = EmailMessageHelper.displayLink(
+ 'change project owner',
+ `${settings.siteUrl}/learn/how-to/How_to_Transfer_Project_Ownership`,
+ isPlainText
+ )
+
+ return [
+ `What does this mean for you?`,
+ `If you accept, you’ll transfer the management of your ${settings.appName} account to the owner of the group subscription, who will then have admin rights over your account and control over your stuff.`,
+ `If you have personal projects in your ${settings.appName} account that you want to keep separate, that’s not a problem. You can set up another account under a personal email address and change the ownership of your personal projects to the new account. Find out how to ${transferProjectOwnershipLink}.`,
+ `If you think this invitation has been sent in error please contact your group administrator.`,
+ ]
+ },
+ ctaURL(opts) {
+ return opts.acceptInviteUrl
+ },
+ ctaText(opts) {
+ return 'Accept invitation'
+ },
+ greeting() {
+ return ''
+ },
+})
+
templates.testEmail = ctaTemplate({
subject() {
return `A Test Email from ${settings.appName}`
diff --git a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js
index 967e59b0a9..4365b93975 100644
--- a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js
+++ b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js
@@ -10,6 +10,8 @@ const {
} = require('../Errors/Errors')
const UserGetter = require('../User/UserGetter')
const UserUpdater = require('../User/UserUpdater')
+const EmailHandler = require('../Email/EmailHandler')
+const logger = require('@overleaf/logger')
/**
* This module contains functions for handling managed users in a
@@ -36,6 +38,8 @@ async function enableManagedUsers(subscriptionId) {
// update the subscription to use the new policy
subscription.groupPolicy = groupPolicy._id
await subscription.save()
+
+ await _sendEmailToGroupMembers(subscriptionId)
}
/**
@@ -145,6 +149,45 @@ async function enrollInSubscription(userId, subscription) {
}
}
+/**
+ * Send email to all group members, irregardless of the member status.
+ * @async
+ * @function
+ * @param {string} subscriptionId - The ID of the subscription to enable
+ * managed users for.
+ * @returns {Promise} - A Promise that resolves when all the `sendEmail` function has been sent,
+ * irregardless of whether they're successful or failed.
+ */
+async function _sendEmailToGroupMembers(subscriptionId) {
+ const EMAIL_DELAY_IN_MS = 0
+
+ const subscription = await Subscription.findById(subscriptionId)
+ .populate('member_ids', 'email')
+ .populate('admin_id', ['first_name', 'last_name', 'email'])
+ .exec()
+
+ // On failure, log the error and carry on so that one email failing does not prevent other emails sending
+ for (const recipient of subscription.member_ids) {
+ try {
+ const opts = {
+ to: recipient.email,
+ admin: subscription.admin_id,
+ groupName: subscription.teamName,
+ }
+ EmailHandler.sendDeferredEmail(
+ 'surrenderAccountForManagedUsers',
+ opts,
+ EMAIL_DELAY_IN_MS
+ )
+ } catch (err) {
+ logger.error(
+ { err, userId: recipient._id },
+ 'could not send notification email to surrender account'
+ )
+ }
+ }
+}
+
module.exports = {
promises: {
enableManagedUsers,