|
- {{TitleFirst}}{{TitleSecondBold}}{{TitleThird}}
+ {{{TitleFirst}}}{{TitleSecondBold}}{{TitleThird}}
|
diff --git a/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs b/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs
index 2b73fc1525..f44274c6a5 100644
--- a/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs
+++ b/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs
@@ -2,4 +2,4 @@
namespace Bit.Core.Models.Data.Organizations;
-public record ClaimedUserDomainClaimedEmails(IEnumerable EmailList, Organization Organization);
+public record ClaimedUserDomainClaimedEmails(IEnumerable EmailList, Organization Organization, string DomainName);
diff --git a/src/Core/Models/Mail/ClaimedDomainUserNotificationViewModel.cs b/src/Core/Models/Mail/ClaimedDomainUserNotificationViewModel.cs
index fa1ed5ab45..deb5571e96 100644
--- a/src/Core/Models/Mail/ClaimedDomainUserNotificationViewModel.cs
+++ b/src/Core/Models/Mail/ClaimedDomainUserNotificationViewModel.cs
@@ -6,4 +6,7 @@ namespace Bit.Core.Models.Mail;
public class ClaimedDomainUserNotificationViewModel : BaseTitleContactUsMailModel
{
public string OrganizationName { get; init; }
+ public string DomainName { get; init; }
+ public string EmailDomain { get; init; }
+ public string UserEmail { get; init; }
}
diff --git a/src/Core/Platform/Mail/HandlebarsMailService.cs b/src/Core/Platform/Mail/HandlebarsMailService.cs
index 179e887a9e..298e335c9f 100644
--- a/src/Core/Platform/Mail/HandlebarsMailService.cs
+++ b/src/Core/Platform/Mail/HandlebarsMailService.cs
@@ -632,16 +632,19 @@ public class HandlebarsMailService : IMailService
public async Task SendClaimedDomainUserEmailAsync(ClaimedUserDomainClaimedEmails emailList)
{
await EnqueueMailAsync(emailList.EmailList.Select(email =>
- CreateMessage(email, emailList.Organization)));
+ CreateMessage(email, emailList.Organization, emailList.DomainName)));
return;
- MailQueueMessage CreateMessage(string emailAddress, Organization org) =>
+ MailQueueMessage CreateMessage(string emailAddress, Organization org, string domainName) =>
new(CreateDefaultMessage($"Important update to your Bitwarden account", emailAddress),
"AdminConsole.DomainClaimedByOrganization",
new ClaimedDomainUserNotificationViewModel
{
- TitleFirst = $"Important update to your Bitwarden account",
- OrganizationName = CoreHelpers.SanitizeForEmail(org.DisplayName(), false)
+ TitleFirst = $"Important update to your Bitwarden account",
+ OrganizationName = CoreHelpers.SanitizeForEmail(org.DisplayName(), false),
+ DomainName = domainName,
+ EmailDomain = emailAddress.Split('@').LastOrDefault() ?? "",
+ UserEmail = emailAddress
});
}
diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs
index ef4c2c941e..730489a9fc 100644
--- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs
+++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs
@@ -282,6 +282,7 @@ public class VerifyOrganizationDomainCommandTests
await sutProvider.GetDependency().Received().SendClaimedDomainUserEmailAsync(
Arg.Is(x =>
x.EmailList.Count(e => e.EndsWith(domain.DomainName)) == mockedUsers.Count &&
- x.Organization.Id == organization.Id));
+ x.Organization.Id == organization.Id &&
+ x.DomainName == domain.DomainName));
}
}
diff --git a/test/Core.Test/Platform/Mail/DomainClaimedEmailRenderTest.cs b/test/Core.Test/Platform/Mail/DomainClaimedEmailRenderTest.cs
new file mode 100644
index 0000000000..57e5f43d8a
--- /dev/null
+++ b/test/Core.Test/Platform/Mail/DomainClaimedEmailRenderTest.cs
@@ -0,0 +1,195 @@
+using Bit.Core.AdminConsole.Entities;
+using Bit.Core.Models.Data.Organizations;
+using Bit.Core.Platform.Mail.Delivery;
+using Bit.Core.Platform.Mail.Enqueuing;
+using Bit.Core.Services.Mail;
+using Bit.Core.Settings;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+using Xunit;
+
+namespace Bit.Core.Test.Platform.Mail;
+
+public class DomainClaimedEmailRenderTest
+{
+ [Fact]
+ public async Task RenderDomainClaimedEmail_ToVerifyTemplate()
+ {
+ var globalSettings = new GlobalSettings
+ {
+ Mail = new GlobalSettings.MailSettings
+ {
+ ReplyToEmail = "no-reply@bitwarden.com",
+ Smtp = new GlobalSettings.MailSettings.SmtpSettings
+ {
+ Host = "localhost",
+ Port = 1025,
+ StartTls = false,
+ Ssl = false
+ }
+ },
+ SiteName = "Bitwarden"
+ };
+
+ var mailDeliveryService = Substitute.For();
+ var mailEnqueuingService = new BlockingMailEnqueuingService();
+ var distributedCache = Substitute.For();
+ var logger = Substitute.For>();
+
+ var mailService = new HandlebarsMailService(
+ globalSettings,
+ mailDeliveryService,
+ mailEnqueuingService,
+ distributedCache,
+ logger
+ );
+
+ var organization = new Organization
+ {
+ Id = Guid.NewGuid(),
+ Name = "Acme Corporation"
+ };
+
+ var testEmails = new List
+ {
+ "alice@acme.com",
+ "bob@acme.com",
+ "charlie@acme.com"
+ };
+
+ var emailList = new ClaimedUserDomainClaimedEmails(
+ testEmails,
+ organization,
+ "acme.com"
+ );
+
+ await mailService.SendClaimedDomainUserEmailAsync(emailList);
+
+ await mailDeliveryService.Received(3).SendEmailAsync(Arg.Any());
+
+ var calls = mailDeliveryService.ReceivedCalls()
+ .Where(call => call.GetMethodInfo().Name == "SendEmailAsync")
+ .ToList();
+
+ Assert.Equal(3, calls.Count);
+
+ foreach (var call in calls)
+ {
+ var mailMessage = call.GetArguments()[0] as Bit.Core.Models.Mail.MailMessage;
+ Assert.NotNull(mailMessage);
+
+ var recipient = mailMessage.ToEmails.First();
+
+ Assert.Contains("@acme.com", mailMessage.HtmlContent);
+ Assert.Contains(recipient, mailMessage.HtmlContent);
+ Assert.DoesNotContain("[at]", mailMessage.HtmlContent);
+ Assert.DoesNotContain("[dot]", mailMessage.HtmlContent);
+ }
+ }
+
+ [Fact(Skip = "For local development - requires MailCatcher at localhost:10250")]
+ public async Task SendDomainClaimedEmail_ToMailCatcher()
+ {
+ var globalSettings = new GlobalSettings
+ {
+ Mail = new GlobalSettings.MailSettings
+ {
+ ReplyToEmail = "no-reply@bitwarden.com",
+ Smtp = new GlobalSettings.MailSettings.SmtpSettings
+ {
+ Host = "localhost",
+ Port = 10250,
+ StartTls = false,
+ Ssl = false
+ }
+ },
+ SiteName = "Bitwarden"
+ };
+
+ var mailDeliveryLogger = Substitute.For>();
+ var mailDeliveryService = new MailKitSmtpMailDeliveryService(globalSettings, mailDeliveryLogger);
+ var mailEnqueuingService = new BlockingMailEnqueuingService();
+ var distributedCache = Substitute.For();
+ var logger = Substitute.For>();
+
+ var mailService = new HandlebarsMailService(
+ globalSettings,
+ mailDeliveryService,
+ mailEnqueuingService,
+ distributedCache,
+ logger
+ );
+
+ var organization = new Organization
+ {
+ Id = Guid.NewGuid(),
+ Name = "Acme Corporation"
+ };
+
+ var testEmails = new List
+ {
+ "alice@acme.com",
+ "bob@acme.com"
+ };
+
+ var emailList = new ClaimedUserDomainClaimedEmails(
+ testEmails,
+ organization,
+ "acme.com"
+ );
+
+ await mailService.SendClaimedDomainUserEmailAsync(emailList);
+ }
+
+ [Fact(Skip = "This test sends actual emails and is for manual template verification only")]
+ public async Task RenderDomainClaimedEmail_WithSpecialCharacters()
+ {
+ var globalSettings = new GlobalSettings
+ {
+ Mail = new GlobalSettings.MailSettings
+ {
+ Smtp = new GlobalSettings.MailSettings.SmtpSettings
+ {
+ Host = "localhost",
+ Port = 1025,
+ StartTls = false,
+ Ssl = false
+ }
+ },
+ SiteName = "Bitwarden"
+ };
+
+ var mailDeliveryService = Substitute.For();
+ var mailEnqueuingService = new BlockingMailEnqueuingService();
+ var distributedCache = Substitute.For();
+ var logger = Substitute.For>();
+
+ var mailService = new HandlebarsMailService(
+ globalSettings,
+ mailDeliveryService,
+ mailEnqueuingService,
+ distributedCache,
+ logger
+ );
+
+ var organization = new Organization
+ {
+ Id = Guid.NewGuid(),
+ Name = "Test Corp & Co."
+ };
+
+ var testEmails = new List
+ {
+ "test.user+tag@example.com"
+ };
+
+ var emailList = new ClaimedUserDomainClaimedEmails(
+ testEmails,
+ organization,
+ "example.com"
+ );
+
+ await mailService.SendClaimedDomainUserEmailAsync(emailList);
+ }
+}
|