ผู้ส่งอีเมลที่เป็นนามธรรมกับผู้ให้บริการเนื้อหา
ฉันได้สร้างผู้ส่งอีเมลกับผู้ให้บริการสำหรับเนื้อหาอีเมลซึ่งจะมีการเปลี่ยนแปลงตามประเภทอีเมล ฉันต้องการความช่วยเหลือเพื่อปรับปรุง
สองรุ่นนี้ใช้ส่ง
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; }
}
ผู้ให้บริการเนื้อหาให้ข้อมูลอีเมลทั้งหมด (หัวเรื่องเนื้อความถึงและสำเนา)
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
การตรวจสอบความถูกต้องเพื่อบังคับ เริ่มต้นเมื่อจำเป็น (เช่นในผู้ส่ง)
การออกแบบโดยรวมของคุณดีพออย่างไรก็ตามคุณสามารถทำได้โดยตรง:
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 (required), To (required), CC (optional), BCC (optional), Subject, and Body เป็นรูปแบบข้อความทั้งหมด เหตุผลเบื้องหลังก็คือมันจะถูกจับคู่กันเสมอตามความต้องการของข้อความใด ๆ ในภายหลังมันจะง่ายกว่าที่จะนำไปใช้ในด้านฐานข้อมูล ใช้IEnumerable<EmailAddress>
จะเปิดใช้งานคอลเลกชันใด ๆ IEnumerable
ที่นำไปปฏิบัติ ดังนั้นจึงไม่ได้ List
จำกัด
สำหรับIEmailProvider
ในฐานะผู้ให้บริการอีเมลควรมีการตั้งค่าของตนเองตามความต้องการ สิ่งนี้จะทำให้คุณง่ายขึ้นในการมีข้อความอีเมลแต่ละฉบับพร้อมการตั้งค่าของตัวเอง ด้วยวิธีนี้คุณสามารถส่งอีเมลหลายฉบับจากผู้ให้บริการที่แตกต่างกันโดยไม่ต้องเข้ารหัสเพิ่มเติม IOptions
ได้รับการปฏิบัติโดยอิสระ แต่ในความเป็นจริงIOptions
จะไม่เป็นประโยชน์ด้วยตัวมันเองและจะใช้โดยEmailProvider
ดังนั้นหากเราเพิ่มลงในสัญญามันจะถูกนำไปใช้กับอินเทอร์เฟซเสมอวิธีนี้คุณบังคับให้ผู้ให้บริการเสมอ มีIOptions
. นอกจากนี้IOptions
ควรเปลี่ยนชื่อเป็นสิ่งที่เหมือนEmailServerSetting
หรือEmailProviderSetting
เพื่อให้เกี่ยวข้องกับการใช้งานหลัก เนื่องจากเป็นการตั้งค่าไม่ใช่ตัวเลือก ใช้IOptions
จัดการการตั้งค่าอีเมลเสริมและคุณสมบัติที่สามารถจัดการได้เช่นส่งเป็นข้อความหรือ html ปิด / เปิดใช้งานไฟล์แนบรูปภาพ .. ฯลฯ
SmtpClient
นอกจากนี้คุณต้องชนชั้นกลางเครื่องห่อสิ่งขึ้นและการใช้งาน นี้จะให้คุณประโยชน์ของการเพิ่มความยืดหยุ่นในการทำงานในปัจจุบันของคุณและห่อไว้ภายใต้หนึ่งหลังคาพร้อมกับสิ่งขึ้นสำหรับโค้ดความสะดวก (เช่นMimeMessage
, TextPart
..etc.) แทน reimplement มันในแต่ละผู้ส่งใหม่ นอกจากนี้ยังช่วยให้คุณสามารถสร้างคอลเลกชันเพื่อจัดเก็บผู้ให้บริการหลายรายหากคุณไปไกล นอกจากนี้คุณจะสามารถเพิ่มผู้ให้บริการรายใหม่จัดการพวกเขาจัดการข้อความและกำหนดขอบเขตงานของคุณได้
นี่คือวิธีที่ฉันจินตนาการถึงการใช้งานขั้นสุดท้าย:
การสร้างผู้ให้บริการใหม่:
// 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();
}