Here is a very crude implementation, but should get you the idea.
Declare your interface for email sender, e.g.
public interface IEmailSender
{
Task SendAsync(string to, string body);
}
Add implementation classes for each flavour, e.g.
public class SmtpEmailSender : IEmailSender
{
private readonly IOptions<SmtpOptions> _options;
private readonly ISmtpClient _client;
public SmtpEmailSender(IOptions<SmtpOptions> options, ISmtpClient client)
{
_options = options;
_client = client;
}
public async Task SendAsync(string to, string body)
{ /* smtp logic */ }
}
public class SendGridEmailSender : IEmailSender
{
private readonly ISendGridClient _sendGridClient;
public SendGridEmailSender(ISendGridClient sendGridClient)
{ _sendGridClient = sendGridClient; }
public async Task SendAsync(string to, string body) { /* smtp logic*/ }
}
public class IMapEmailSender : IEmailSender
{
public async Task SendAsync(string to, string body) { ... }
}
Each of these can have its own dependencies as you wish.
Add a factory class (with an interface too if you want. left that out to keep it simple)
public class EmailSenderFactory
{
private readonly IServiceProvider _serviceProvider;
public EmailSenderFactory(IServiceProvider serviceProvider)
{ _serviceProvider = serviceProvider; }
public IEmailSender GetEmailSender(string senderType)
{
return senderType switch
{
"smtp" => _serviceProvider.GetRequiredService<SmtpEmailSender>(),
"sendgrid" => _serviceProvider.GetRequiredService<SendGridEmailSender>(),
"imap" => _serviceProvider.GetRequiredService<IMapEmailSender>(),
"other" => _serviceProvider.GetRequiredService<OtherType>(),
_ => throw new Exception("No sender configured for this") // handle case of provider not found
};
}
}
Register each of the implementations, including the factory class.
builder.Services.AddScoped<SendGridEmailSender>(); // or service.Add if in Startup.cs
builder.Services.AddScoped<IMapEmailSender>();
builder.Services.AddScoped<SmtpEmailSender>();
builder.Services.AddScoped<EmailSenderFactory>();
In your usage, inject EmailSenderFactory
and resolve an IEmailSender
from there.
public class SomeController
{
private readonly EmailSenderFactory _factory;
public SomeController(EmailSenderFactory factory)
{ _factory = factory; }
[HttpPost]
public async Task<ActionResult> SendEmail(RequestModel requestModel)
{
var sender = _factory.GetEmailSender(requestModel.ProviderType);
await sender.SendAsync(...);
}
}