콘텐츠 제공 업체가있는 추상화 된 이메일 발신자

Aug 17 2020

이메일 콘텐츠 제공 업체와 함께 이메일 발신자를 만들었으며 이메일 유형에 따라 변경됩니다. 개선하려면 도움이 필요합니다.

이 두 모델은

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단일 메소드 가있는 추상화 된 이메일 발신자 가 있습니다.SendIEmailContentProvider

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"));
    }
}

답변

1 iSR5 Sep 01 2020 at 03:40
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 (선택), Subject 및 Body를 포함해야합니다. 그 이유는 모든 메시지에 대한 요구 사항으로 항상 함께 쌍을 이루고 나중에 데이터베이스 측에서 구현하는 것이 더 쉬울 것이기 때문입니다. using IEnumerable<EmailAddress>IEnumerable. 따라서 List.

대한 IEmailProvider이메일 제공 업체는 요구 사항으로 자신의 설정을 포함해야한다. 이렇게하면 각 이메일 메시지에 고유 한 설정이 포함되어있어 작업이 더 쉬워집니다. 이렇게하면 별도의 코딩없이 여러 제공 업체에서 여러 이메일을 보낼 수 있습니다. IOptions독립적으로 처리되지만 실제로 IOptions는 그 자체로는 유용하지 않으며에서만 사용 EmailProvider되므로 계약에 추가하면 항상 인터페이스로 구현됩니다. 이렇게하면 공급자가 항상 있다 IOptions. 게다가, 주요 구현과 관련 되거나 IOptions유사한 이름으로 변경되어야합니다 . 이것은 옵션이 아니라 설정이기 때문입니다. 텍스트 또는 html로 보내기, 첨부 파일, 그림 등을 비활성화 / 활성화하는 등 관리 할 수있는 이메일 선택적 설정 및 기능을 처리하는 데 사용 합니다.EmailServerSettingEmailProviderSettingIOptions

또한 일을 마무리하기 위해 미들웨어 클래스가 필요하고 SmtpClient. 이것은 현재 작업의 유연성을 증가 당신에게 이점을 제공하고 코드를 재사용하기 위해 쉽게와 함께 한 지붕 아래에서 일을을 마무리 것이다 (예 MimeMessage, 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();  
}