Người gửi email tóm tắt với các nhà cung cấp nội dung
Tôi đã tạo một người gửi email với các nhà cung cấp cho nội dung email, nội dung này sẽ được thay đổi dựa trên loại email. Tôi cần một số trợ giúp để nâng cao nó.
Hai mô hình này được sử dụng để gửi
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; }
}
Nhà cung cấp nội dung cung cấp tất cả thông tin email (chủ đề, nội dung, Tới và Cc)
public interface IEmailContentProvider
{
EmailMessage Message { get; }
}
Sau đó, chúng tôi có người gửi email được tóm tắt IEmailSendercó một phương thức duy nhất Sendsử dụng IEmailContentProvidertham số để lấy thông tin email
interface IEmailSender
{
Task Send(IEmailContentProvider provider);
}
Tôi có một ví dụ cho nhà cung cấp nội dung 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} }
};
}
}
Việc IEmailSenderthực hiện:
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);
}
}
Và đây là, cách sử dụng nó và gửi 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"));
}
}
Trả lời
public EmailMessage()
{
ToAddresses = new List<EmailAddress>();
CcAddresses = new List<EmailAddress>();
}
Không cần thiết, tôi có thể hiểu nếu bạn chỉ khởi tạo ToAddress, tuy nhiên, việc khởi tạo các danh sách như thế này có thể tiêu tốn rất nhiều bộ nhớ (hãy tưởng tượng bạn có một lượng lớn các EmailMessagephiên bản! Vì vậy, tôi khuyên bạn nên giữ chúng ở dạng null và sử dụng nullxác thực để buộc khởi tạo chúng khi cần thiết (như ở người gửi).
thiết kế tổng thể của bạn đủ tốt, tuy nhiên, bạn có thể làm điều này trực tiếp:
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; }
}
EmailMessagephải chứa Từ (bắt buộc), Đến (bắt buộc), CC (tùy chọn), BCC (tùy chọn), Chủ đề và Nội dung dưới dạng mô hình đầy đủ của thông báo. Lý do đằng sau đó là nó sẽ luôn được ghép nối với nhau theo yêu cầu đối với bất kỳ thông báo nào, về sau, nó cũng sẽ dễ thực hiện hơn trên phía cơ sở dữ liệu. sử dụng IEnumerable<EmailAddress>sẽ mở để sử dụng bất kỳ bộ sưu tập nào triển khai IEnumerable. Vì vậy, nó không bị hạn chế List.
Đối với IEmailProviderNhư một nhà cung cấp email cũng nên có các cài đặt riêng theo yêu cầu. Điều này sẽ làm mọi thứ dễ dàng hơn cho bạn, mỗi email có cài đặt riêng. Bằng cách này, bạn có thể gửi nhiều email từ các nhà cung cấp khác nhau mà không cần mã hóa thêm. IOptionsđược xử lý độc lập, nhưng trên thực tế, IOptionsbản thân nó sẽ không hữu ích và nó sẽ chỉ được sử dụng bởi EmailProvider, vì vậy nếu chúng tôi thêm nó vào hợp đồng, nó sẽ luôn được triển khai với giao diện, theo cách này, bạn đã buộc nhà cung cấp luôn có IOptions. Bên cạnh đó, IOptionsnên được đổi tên thành một cái gì đó giống như EmailServerSettinghoặc EmailProviderSettingđể liên quan đến việc triển khai chính. Vì đây là cài đặt chứ không phải tùy chọn. Sử dụng IOptionsđể xử lý các cài đặt tùy chọn email và các tính năng có thể được quản lý như gửi dưới dạng văn bản hoặc html, tắt / bật tệp đính kèm, hình ảnh .. vv.
Ngoài ra, bạn cần một lớp trung lưu để gói gọn mọi thứ và sử dụng SmtpClient. Điều này sẽ mang lại cho bạn lợi thế là tăng tính linh hoạt của công việc hiện tại và bọc chúng dưới một mái nhà cùng với việc dễ dàng sử dụng lại mã (chẳng hạn như MimeMessage, TextPart.. v.v.) thay vì thực hiện lại trên mỗi người gửi mới. Nó cũng sẽ cung cấp cho bạn khả năng tạo một bộ sưu tập để lưu trữ nhiều nhà cung cấp nếu bạn đang đi xa đến mức đó. ngoài ra, bạn sẽ có thể thêm các nhà cung cấp mới, xử lý chúng, xử lý tin nhắn và duy trì phạm vi công việc của bạn.
Đây là cách tôi hình dung cách sử dụng cuối cùng:
Tạo nhà cung cấp mới:
// 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
}
bây giờ, tạo một thư mới và gửi nó:
// 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();
}