コンテンツプロバイダーによる抽象化された電子メール送信者
メールコンテンツのプロバイダーを含むメール送信者を作成しました。これは、メールの種類に基づいて変更されます。私はそれを強化するためにいくつかの助けが必要です。
これらの2つのモデルは送信に使用されます
public class EmailAddress
{
public string Name { get; set; }
public string Address { get; set; }
}
public class EmailMessage
{
public EmailMessage()
{
ToAddresses = new List<EmailAddress>();
CcAddresses = new List<EmailAddress>();
}
public List<EmailAddress> ToAddresses { get; set; }
public List<EmailAddress> CcAddresses { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
}
コンテンツプロバイダーは、すべての電子メール情報(件名、本文、宛先、およびCc)を提供します。
public interface IEmailContentProvider
{
EmailMessage Message { get; }
}
次に、パラメータを使用して電子メール情報を取得IEmailSender
する単一のメソッドSend
を持つ抽象化された電子メール送信者がありIEmailContentProvider
ます
interface IEmailSender
{
Task Send(IEmailContentProvider provider);
}
コンテンツプロバイダーの例があります WelcomEmailProvider
public class WelcomEmailProvider : IEmailProvider
{
public EmailMessage Message { get; }
public WelcomEmailProvider(string address, string name)
{
Message = new EmailMessage
{
Subject = $"Welcome {name}", Content = $"This is welcome email provider!",
ToAddresses = new List<EmailAddress> { new EmailAddress { Address = address, Name = name} }
};
}
}
IEmailSender
実装:
public class EmailSender : IEmailSender
{
private readonly SmtpOptions _options;
public EmailSender(IOptions<SmtpOptions> options)
{
_options = options.Value;
}
public async Task Send(IEmailContentProvider provider)
{
var emailMessage = provider.Message;
var message = new MimeMessage();
message.From.Add(new MailboxAddress(_options.Sender.Name, _options.Sender.Address));
message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
message.Cc.AddRange(emailMessage.CcAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
message.Subject = emailMessage.Subject;
message.Body = new TextPart(TextFormat.Html) { Text = emailMessage.Content };
using var emailClient = new SmtpClient();
await emailClient.ConnectAsync(_options.Server, _options.Port, _options.EnableSsl);
await AuthenticatedData(emailClient);
await emailClient.SendAsync(message);
await emailClient.DisconnectAsync(true);
}
private async Task AuthenticatedData(SmtpClient smtpClient)
{
if (string.IsNullOrWhiteSpace(_options.Username) || string.IsNullOrWhiteSpace(_options.Password))
return;
emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
await emailClient.AuthenticateAsync(_options.Username, _options.Password);
}
}
そして、これがそれを使用して電子メールを送信する方法です:
class Sample
{
private readonly IEmailSender _emailSender;
public Samole(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public async Task DoSomethingThenSendEmail()
{
await _emailSender.Send(new WelcomEmailProvider("[email protected]", "Someone"));
}
}
回答
public EmailMessage()
{
ToAddresses = new List<EmailAddress>();
CcAddresses = new List<EmailAddress>();
}
必須ではありませんが、開始しただけで理解できますToAddress
が、このようなリストを開始すると、大量のメモリを消費する可能性があります(EmailMessage
インスタンスが大量にあると想像してください!したがって、それらをnullのままにして、null
検証を使用して強制することをお勧めします(送信者のように)必要なときにそれらを開始します。
全体的なデザインは十分ですが、これを直接行うことができます。
public class EmailMessage
{
public EmailAddress From { get; set; }
public IEnumerable<EmailAddress> To { get; set; }
public IEnumerable<EmailAddress> Cc { get; set; }
public IEnumerable<EmailAddress> Bcc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public interface IEmailProvider
{
IEmailServerSetting ServerSettings { get; set; }
}
EmailMessage
メッセージの完全なモデルとして、From(必須)、To(必須)、CC(オプション)、BCC(オプション)、件名、および本文を含める必要があります。その背後にある理由は、メッセージの要件として常にペアになり、後でデータベース側で実装するのも簡単になるためです。usingIEnumerable<EmailAddress>
は、を実装する任意のコレクションを使用するために開きますIEnumerable
。したがって、に限定されませんList
。
以下のためのIEmailProvider
電子メールプロバイダも要件として独自の設定を含める必要があります。これにより、各電子メールメッセージに独自の設定を設定することが容易になります。このようにして、追加のコーディングなしで、異なるプロバイダーから複数の電子メールを送信できます。IOptions
は独立して扱われますが、実際にIOptions
はそれ自体では役に立たず、によってのみ使用されるEmailProvider
ため、コントラクトに追加すると、常にインターフェイスで実装されます。このようにして、プロバイダーに常に持っていIOptions
ます。また、IOptions
のようなものに名前を変更しなければならないEmailServerSetting
か、EmailProviderSetting
メインの実装にそれを関連付けるために。これらは設定であり、オプションではありません。IOptions
テキストやHTMLとして送信したり、添付ファイルや写真などを無効/有効にしたりするなど、管理できるメールのオプション設定や機能を処理するために使用します。
また、物事をまとめるためのミドルウェアクラスが必要であり、を使用しSmtpClient
ます。これにより、現在の作業の柔軟性が高まり、新しい送信者ごとにコードを再実装するのではなくMimeMessage
、コードを再利用するための作業が簡単になるとともに、それらを1つの屋根の下にラップするという利点が得られますTextPart
。また、これまでのところ、複数のプロバイダーを格納するためのコレクションを作成することもできます。また、新しいプロバイダーを追加し、それらを処理し、メッセージを処理し、作業の範囲を維持することができます。
これが私が最終的な使用法を想像する方法です:
新しいプロバイダーの作成:
// creating a new email provider
public class SomeEmailProvider : IEmailProvider
{
// only set the settings internally but it's exposed to be readonly
public EmailServerSetting ServerSettings { get; private set; }
public SomeEmailProvider()
{
//set up the server settings
ServerSettings = new EmailServerSetting
{
ServerType = EmailServerType.POP,
Server = "pop.mail.com",
Port = 995,
Encryption = EmailServerEncryption.SSLOrTLS,
EnableSsl = true
};
}
// some other related code
}
今、新しいメールメッセージを作成して送信します:
// can be single object or collection
var messages = new EmailMessage
{
From = new EmailAddress("Test", "[email protected]"),
To = new EmailAddress [] {
new EmailAddress("Test1", "[email protected]"),
new EmailAddress("Test2", "[email protected]")
},
Subject = "Testing Subject",
Body = "Normal Text Body"
};
using(var client = new EmailClient(new SomeEmailProvider()))
{
client.Options = new EmailClientOptions
{
// would send it as plain text
EnableHtml = false
};
client.Messages.Add(messages);
client.Send();
}