Pengirim email abstrak dengan penyedia konten
Saya telah membuat pengirim email dengan penyedia konten email, yang akan diubah berdasarkan jenis email. Saya butuh bantuan untuk meningkatkannya.
Kedua model ini digunakan untuk mengirim
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; }
}
Penyedia konten menyediakan semua informasi email (subjek, isi, Kepada dan Cc)
public interface IEmailContentProvider
{
EmailMessage Message { get; }
}
Kemudian kami memiliki pengirim email abstrak IEmailSender
yang memiliki metode tunggal Send
yang menggunakan IEmailContentProvider
parameter untuk mendapatkan informasi email
interface IEmailSender
{
Task Send(IEmailContentProvider provider);
}
Saya punya contoh untuk penyedia konten 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} }
};
}
}
The IEmailSender
implementasi:
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);
}
}
Dan inilah, cara menggunakannya dan mengirim email:
class Sample
{
private readonly IEmailSender _emailSender;
public Samole(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public async Task DoSomethingThenSendEmail()
{
await _emailSender.Send(new WelcomEmailProvider("[email protected]", "Someone"));
}
}
Jawaban
public EmailMessage()
{
ToAddresses = new List<EmailAddress>();
CcAddresses = new List<EmailAddress>();
}
Tidak perlu, saya dapat mengerti jika Anda baru saja memulai ToAddress
, namun, memulai daftar seperti ini mungkin menghabiskan banyak memori (bayangkan Anda memiliki jumlah EmailMessage
contoh yang besar! Jadi, saya sarankan untuk menyimpannya sebagai null, dan gunakan null
validasi untuk memaksa memulai mereka saat dibutuhkan (seperti di pengirim).
keseluruhan desain Anda sudah cukup bagus, namun Anda dapat melakukannya secara langsung:
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
harus berisi Dari (wajib), Kepada (wajib), CC (opsional), BCC (opsional), Subjek, dan Isi sebagai model lengkap pesan. Alasan di balik itu adalah bahwa itu akan selalu dipasangkan bersama sebagai persyaratan untuk pesan apa pun, nantinya juga akan lebih mudah diimplementasikan di sisi database. menggunakan IEnumerable<EmailAddress>
akan terbuka untuk menggunakan koleksi apa pun yang mengimplementasikan IEnumerable
. Jadi, itu tidak terbatas pada List
.
Karena IEmailProvider
Sebagai penyedia email juga harus memuat pengaturannya sendiri sebagai persyaratan. Ini akan mempermudah Anda, untuk memiliki setiap pesan email dengan pengaturannya sendiri. Dengan cara ini, Anda dapat mengirim banyak email dari penyedia yang berbeda tanpa pengkodean tambahan. IOptions
diperlakukan secara independen, tetapi pada kenyataannya, IOptions
tidak akan berguna dengan sendirinya, dan hanya akan digunakan oleh EmailProvider
, jadi jika kami menambahkannya ke kontrak, itu akan selalu diimplementasikan dengan antarmuka, dengan cara ini Anda memaksa penyedia untuk selalu punya IOptions
. Selain itu, IOptions
harus diubah namanya menjadi sesuatu seperti EmailServerSetting
atau EmailProviderSetting
mengaitkannya dengan implementasi utama. Karena ini adalah pengaturan dan bukan opsi. MenggunakanIOptions
untuk menangani pengaturan opsional email dan fitur yang dapat dikelola seperti mengirim sebagai teks atau html, nonaktifkan / aktifkan lampiran, gambar .. dll.
Juga, Anda membutuhkan kelas menengah untuk menyelesaikan semuanya, dan menggunakan SmtpClient
. Ini akan memberi Anda keuntungan dalam meningkatkan fleksibilitas pekerjaan Anda saat ini dan menggabungkannya di bawah satu atap bersama dengan kemudahan untuk menggunakan kembali kode (seperti MimeMessage
, TextPart
..etc.) Daripada menerapkannya kembali pada setiap pengirim baru. Ini juga akan memberi Anda kemampuan untuk membuat koleksi untuk menyimpan banyak penyedia jika Anda melangkah sejauh itu. juga, Anda akan dapat menambahkan penyedia baru, menanganinya, menangani pesan, dan menjaga cakupan pekerjaan Anda.
Berikut adalah bagaimana saya membayangkan penggunaan akhir:
Membuat penyedia baru:
// 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
}
sekarang, membuat pesan email baru dan mengirimkannya:
// 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();
}