Merge pull request #10393 from umbraco/v9/feature/email-display-name-in-notifiaction
V9: Add new email Model for notifications
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
|
||||
namespace Umbraco.Cms.Core.Events
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Mail;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
|
||||
namespace Umbraco.Cms.Core.Mail
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
|
||||
namespace Umbraco.Cms.Core.Mail
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
namespace Umbraco.Cms.Core.Models.Email
|
||||
{
|
||||
public class EmailMessage
|
||||
{
|
||||
@@ -33,7 +33,6 @@ namespace Umbraco.Cms.Core.Models
|
||||
|
||||
public EmailMessage(string from, string[] to, string[] cc, string[] bcc, string[] replyTo, string subject, string body, bool isBodyHtml, IEnumerable<EmailMessageAttachment> attachments)
|
||||
{
|
||||
ArgumentIsNotNullOrEmpty(from, nameof(from));
|
||||
ArgumentIsNotNullOrEmpty(to, nameof(to));
|
||||
ArgumentIsNotNullOrEmpty(subject, nameof(subject));
|
||||
ArgumentIsNotNullOrEmpty(body, nameof(body));
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
namespace Umbraco.Cms.Core.Models.Email
|
||||
{
|
||||
public class EmailMessageAttachment
|
||||
{
|
||||
18
src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs
Normal file
18
src/Umbraco.Core/Models/Email/NotificationEmailAddress.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Umbraco.Cms.Core.Models.Email
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an email address used for notifications. Contains both the address and its display name.
|
||||
/// </summary>
|
||||
public class NotificationEmailAddress
|
||||
{
|
||||
public string DisplayName { get; }
|
||||
|
||||
public string Address { get; }
|
||||
|
||||
public NotificationEmailAddress(string address, string displayName)
|
||||
{
|
||||
Address = address;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/Umbraco.Core/Models/Email/NotificationEmailModel.cs
Normal file
54
src/Umbraco.Core/Models/Email/NotificationEmailModel.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models.Email
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an email when sent with notifications.
|
||||
/// </summary>
|
||||
public class NotificationEmailModel
|
||||
{
|
||||
public NotificationEmailAddress From { get; }
|
||||
|
||||
public IEnumerable<NotificationEmailAddress> To { get; }
|
||||
|
||||
public IEnumerable<NotificationEmailAddress> Cc { get; }
|
||||
|
||||
public IEnumerable<NotificationEmailAddress> Bcc { get; }
|
||||
|
||||
public IEnumerable<NotificationEmailAddress> ReplyTo { get; }
|
||||
|
||||
public string Subject { get; }
|
||||
|
||||
public string Body { get; }
|
||||
|
||||
public bool IsBodyHtml { get; }
|
||||
|
||||
public IList<EmailMessageAttachment> Attachments { get; }
|
||||
|
||||
public bool HasAttachments => Attachments != null && Attachments.Count > 0;
|
||||
|
||||
public NotificationEmailModel(
|
||||
NotificationEmailAddress from,
|
||||
IEnumerable<NotificationEmailAddress> to,
|
||||
IEnumerable<NotificationEmailAddress> cc,
|
||||
IEnumerable<NotificationEmailAddress> bcc,
|
||||
IEnumerable<NotificationEmailAddress> replyTo,
|
||||
string subject,
|
||||
string body,
|
||||
IEnumerable<EmailMessageAttachment> attachments,
|
||||
bool isBodyHtml)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
Cc = cc;
|
||||
Bcc = bcc;
|
||||
ReplyTo = replyTo;
|
||||
Subject = subject;
|
||||
Body = body;
|
||||
IsBodyHtml = isBodyHtml;
|
||||
Attachments = attachments?.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
|
||||
namespace Umbraco.Cms.Core.Notifications
|
||||
{
|
||||
public class SendEmailNotification : INotification
|
||||
{
|
||||
public SendEmailNotification(EmailMessage message) => Message = message;
|
||||
public SendEmailNotification(NotificationEmailModel message) => Message = message;
|
||||
|
||||
public EmailMessage Message { get; set; }
|
||||
public NotificationEmailModel Message { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Mail;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Infrastructure.Extensions;
|
||||
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
||||
@@ -53,7 +53,8 @@ namespace Umbraco.Cms.Infrastructure
|
||||
{
|
||||
if (enableNotification)
|
||||
{
|
||||
await _eventAggregator.PublishAsync(new SendEmailNotification(message));
|
||||
await _eventAggregator.PublishAsync(
|
||||
new SendEmailNotification(message.ToNotificationEmail(_globalSettings.Smtp?.From)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MimeKit;
|
||||
using MimeKit.Text;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Extensions
|
||||
{
|
||||
@@ -9,13 +10,9 @@ namespace Umbraco.Cms.Infrastructure.Extensions
|
||||
{
|
||||
public static MimeMessage ToMimeMessage(this EmailMessage mailMessage, string configuredFromAddress)
|
||||
{
|
||||
var fromEmail = mailMessage.From;
|
||||
if (string.IsNullOrEmpty(fromEmail))
|
||||
{
|
||||
fromEmail = configuredFromAddress;
|
||||
}
|
||||
var fromEmail = string.IsNullOrEmpty(mailMessage.From) ? configuredFromAddress : mailMessage.From;
|
||||
|
||||
if (!InternetAddress.TryParse(mailMessage.From, out InternetAddress fromAddress))
|
||||
if (!InternetAddress.TryParse(fromEmail, out InternetAddress fromAddress))
|
||||
{
|
||||
throw new ArgumentException($"Email could not be sent. Could not parse from address {fromEmail} as a valid email address.");
|
||||
}
|
||||
@@ -78,5 +75,57 @@ namespace Umbraco.Cms.Infrastructure.Extensions
|
||||
throw new InvalidOperationException($"Email could not be sent. Could not parse a valid recipient address.");
|
||||
}
|
||||
}
|
||||
|
||||
public static NotificationEmailModel ToNotificationEmail(this EmailMessage emailMessage,
|
||||
string configuredFromAddress)
|
||||
{
|
||||
var fromEmail = string.IsNullOrEmpty(emailMessage.From) ? configuredFromAddress : emailMessage.From;
|
||||
|
||||
NotificationEmailAddress from = ToNotificationAddress(fromEmail);
|
||||
|
||||
return new NotificationEmailModel(from,
|
||||
GetNotificationAddresses(emailMessage.To),
|
||||
GetNotificationAddresses(emailMessage.Cc),
|
||||
GetNotificationAddresses(emailMessage.Bcc),
|
||||
GetNotificationAddresses(emailMessage.ReplyTo),
|
||||
emailMessage.Subject,
|
||||
emailMessage.Body,
|
||||
emailMessage.Attachments,
|
||||
emailMessage.IsBodyHtml);
|
||||
}
|
||||
|
||||
private static NotificationEmailAddress ToNotificationAddress(string address)
|
||||
{
|
||||
if (InternetAddress.TryParse(address, out InternetAddress internetAddress))
|
||||
{
|
||||
if (internetAddress is MailboxAddress mailboxAddress)
|
||||
{
|
||||
return new NotificationEmailAddress(mailboxAddress.Address, internetAddress.Name);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<NotificationEmailAddress> GetNotificationAddresses(IEnumerable<string> addresses)
|
||||
{
|
||||
if (addresses is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var notificationAddresses = new List<NotificationEmailAddress>();
|
||||
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
NotificationEmailAddress notificationAddress = ToNotificationAddress(address);
|
||||
if (notificationAddress is not null)
|
||||
{
|
||||
notificationAddresses.Add(notificationAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return notificationAddresses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Mail;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Infrastructure.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions
|
||||
@@ -24,9 +25,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions
|
||||
const string subject = "Subject";
|
||||
const string body = "<p>Message</p>";
|
||||
const bool isBodyHtml = true;
|
||||
var emailMesasge = new EmailMessage(from, to, subject, body, isBodyHtml);
|
||||
var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml);
|
||||
|
||||
var result = emailMesasge.ToMimeMessage(ConfiguredSender);
|
||||
var result = emailMessage.ToMimeMessage(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual(1, result.From.Count());
|
||||
Assert.AreEqual(from, result.From.First().ToString());
|
||||
@@ -54,9 +55,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions
|
||||
{
|
||||
new EmailMessageAttachment(attachmentStream, "test.txt"),
|
||||
};
|
||||
var emailMesasge = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments);
|
||||
var emailMessage = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments);
|
||||
|
||||
var result = emailMesasge.ToMimeMessage(ConfiguredSender);
|
||||
var result = emailMessage.ToMimeMessage(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual(1, result.From.Count());
|
||||
Assert.AreEqual(from, result.From.First().ToString());
|
||||
@@ -77,5 +78,147 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Extensions
|
||||
Assert.AreEqual(body, result.TextBody.ToString());
|
||||
Assert.AreEqual(1, result.Attachments.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Construct_MimeMessage_With_ConfiguredSender()
|
||||
{
|
||||
const string to = "to@email.com";
|
||||
const string subject = "Subject";
|
||||
const string body = "<p>Message</p>";
|
||||
const bool isBodyHtml = true;
|
||||
var emailMessage = new EmailMessage(null, to, subject, body, isBodyHtml);
|
||||
|
||||
var result = emailMessage.ToMimeMessage(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual(1, result.From.Count());
|
||||
Assert.AreEqual(ConfiguredSender, result.From.First().ToString());
|
||||
Assert.AreEqual(1, result.To.Count());
|
||||
Assert.AreEqual(to, result.To.First().ToString());
|
||||
Assert.AreEqual(subject, result.Subject);
|
||||
Assert.IsNull(result.TextBody);
|
||||
Assert.AreEqual(body, result.HtmlBody.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage()
|
||||
{
|
||||
const string from = "from@email.com";
|
||||
const string to = "to@email.com";
|
||||
const string subject = "Subject";
|
||||
const string body = "<p>Message</p>";
|
||||
const bool isBodyHtml = true;
|
||||
var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml);
|
||||
|
||||
NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual(from, result.From.Address);
|
||||
Assert.AreEqual("", result.From.DisplayName);
|
||||
Assert.AreEqual(1, result.To.Count());
|
||||
Assert.AreEqual(to, result.To.First().Address);
|
||||
Assert.AreEqual("", result.To.First().DisplayName);
|
||||
Assert.AreEqual(subject, result.Subject);
|
||||
Assert.AreEqual(body, result.Body);
|
||||
Assert.IsTrue(result.IsBodyHtml);
|
||||
Assert.IsFalse(result.HasAttachments);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage_With_Configured_Sender()
|
||||
{
|
||||
const string to = "to@email.com";
|
||||
const string subject = "Subject";
|
||||
const string body = "<p>Message</p>";
|
||||
const bool isBodyHtml = true;
|
||||
var emailMessage = new EmailMessage(null, to, subject, body, isBodyHtml);
|
||||
|
||||
NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual(ConfiguredSender, result.From.Address);
|
||||
Assert.AreEqual("", result.From.DisplayName);
|
||||
Assert.AreEqual(1, result.To.Count());
|
||||
Assert.AreEqual(to, result.To.First().Address);
|
||||
Assert.AreEqual("", result.To.First().DisplayName);
|
||||
Assert.AreEqual(subject, result.Subject);
|
||||
Assert.AreEqual(body, result.Body);
|
||||
Assert.IsTrue(result.IsBodyHtml);
|
||||
Assert.IsFalse(result.HasAttachments);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Construct_NotificationEmailModel_From_Simple_MailMessage_With_DisplayName()
|
||||
{
|
||||
const string from = "\"From Email\" <from@from.com>";
|
||||
const string to = "\"To Email\" <to@to.com>";
|
||||
const string subject = "Subject";
|
||||
const string body = "<p>Message</p>";
|
||||
const bool isBodyHtml = true;
|
||||
var emailMessage = new EmailMessage(from, to, subject, body, isBodyHtml);
|
||||
|
||||
NotificationEmailModel result = emailMessage.ToNotificationEmail(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual("from@from.com", result.From.Address);
|
||||
Assert.AreEqual("From Email", result.From.DisplayName);
|
||||
Assert.AreEqual(1, result.To.Count());
|
||||
Assert.AreEqual("to@to.com", result.To.First().Address);
|
||||
Assert.AreEqual("To Email", result.To.First().DisplayName);
|
||||
Assert.AreEqual(subject, result.Subject);
|
||||
Assert.AreEqual(body, result.Body);
|
||||
Assert.IsTrue(result.IsBodyHtml);
|
||||
Assert.IsFalse(result.HasAttachments);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Construct_NotificationEmailModel_From_Full_EmailMessage()
|
||||
{
|
||||
const string from = "\"From Email\" <from@from.com>";
|
||||
string[] to = { "to@email.com", "\"Second Email\" <to2@email.com>", "invalid@invalid@invalid" };
|
||||
string[] cc = { "\"First CC\" <cc@email.com>", "cc2@email.com", "invalid@invalid@invalid" };
|
||||
string[] bcc = { "bcc@email.com", "bcc2@email.com", "\"Third BCC\" <bcc3@email.com>", "invalid@email@address" };
|
||||
string[] replyTo = { "replyto@email.com", "invalid@invalid@invalid" };
|
||||
const string subject = "Subject";
|
||||
const string body = "Message";
|
||||
const bool isBodyHtml = false;
|
||||
|
||||
using var attachmentStream = new MemoryStream(Encoding.UTF8.GetBytes("test"));
|
||||
var attachments = new List<EmailMessageAttachment>
|
||||
{
|
||||
new EmailMessageAttachment(attachmentStream, "test.txt"),
|
||||
};
|
||||
var emailMessage = new EmailMessage(from, to, cc, bcc, replyTo, subject, body, isBodyHtml, attachments);
|
||||
|
||||
var result = emailMessage.ToNotificationEmail(ConfiguredSender);
|
||||
|
||||
Assert.AreEqual("from@from.com", result.From.Address);
|
||||
Assert.AreEqual("From Email", result.From.DisplayName);
|
||||
|
||||
Assert.AreEqual(2, result.To.Count());
|
||||
Assert.AreEqual("to@email.com", result.To.First().Address);
|
||||
Assert.AreEqual("", result.To.First().DisplayName);
|
||||
Assert.AreEqual("to2@email.com", result.To.Skip(1).First().Address);
|
||||
Assert.AreEqual("Second Email", result.To.Skip(1).First().DisplayName);
|
||||
|
||||
Assert.AreEqual(2, result.Cc.Count());
|
||||
Assert.AreEqual("cc@email.com", result.Cc.First().Address);
|
||||
Assert.AreEqual("First CC", result.Cc.First().DisplayName);
|
||||
Assert.AreEqual("cc2@email.com", result.Cc.Skip(1).First().Address);
|
||||
Assert.AreEqual("", result.Cc.Skip(1).First().DisplayName);
|
||||
|
||||
Assert.AreEqual(3, result.Bcc.Count());
|
||||
Assert.AreEqual("bcc@email.com", result.Bcc.First().Address);
|
||||
Assert.AreEqual("", result.Bcc.First().DisplayName);
|
||||
Assert.AreEqual("bcc2@email.com", result.Bcc.Skip(1).First().Address);
|
||||
Assert.AreEqual("", result.Bcc.Skip(1).First().DisplayName);
|
||||
Assert.AreEqual("bcc3@email.com", result.Bcc.Skip(2).First().Address);
|
||||
Assert.AreEqual("Third BCC", result.Bcc.Skip(2).First().DisplayName);
|
||||
|
||||
Assert.AreEqual(1, result.ReplyTo.Count());
|
||||
Assert.AreEqual("replyto@email.com", result.ReplyTo.First().Address);
|
||||
Assert.AreEqual("", result.ReplyTo.First().DisplayName);
|
||||
|
||||
Assert.AreEqual(subject, result.Subject);
|
||||
Assert.AreEqual(body, result.Body);
|
||||
Assert.AreEqual(1, result.Attachments.Count());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ using Umbraco.Cms.Core.Mail;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Net;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
|
||||
@@ -26,6 +26,7 @@ using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.Email;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
Reference in New Issue
Block a user