Search code examples
c#asp.net.netsmtpautomapper

Send Email To Admin


I need to send a lot of different forms to the mail. For example FeedBackForm ContactsForm. the only difference is that I create different mail.Subject and mail.Body.

I need to automate this action.

public class EmailService : IEmailService, ITransientService
{
    private IConfiguration _configuration;

    public EmailService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public async Task SendFormToAdminEmailAsync (FeedBackForm form)
    {
        var fromAddress = _configuration["EmailCredentials:Email"];
        var fromPassword = _configuration["EmailCredentials:Password"];

        var toAddress = new MailAddress("[email protected]");

        var mail = new MailMessage(new MailAddress(fromAddress), toAddress);

        mail.Subject = $"Need consultation {form.Name}";
        mail.Body = $@"Name:  {form.Name}
                       Email: {form.Email}
                       Phone: {form.PhoneNumber}
                       Link:  {form.BotLink}";

        using (SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587))
        {
            smtp.Credentials = new NetworkCredential("[email protected]", fromPassword);
            smtp.EnableSsl = true;

            await smtp.SendMailAsync(mail);
        }
    }
}

I tried this, in this method I accepted a generic type, and with the help of automapper I mapped what I needed, and specified the conditions in MappingConfig, but I don’t know if this is correct


Solution

  • The way I'd proceed would be to (if you don't already have it) create an interface for forms (FeedbackForm, ContactForm)

    interface IFormData
    {
        // Don't know if you have some common ground on forms
        // This may be an empty interface to mark types that can be worked with
        // in later stages of this solution.
    }
    

    You can create an interface like:

    interface IMailHydrator
    {
        void Hydrate(MailMessage message, IFormData form);
    }
    

    And than you create implementation like

    class FeedBackFormHydrator : IMailHydrator
    {
        public void Hydrate(MailMessage message, IFormData form)
        {
            var cast = form as FeedBackForm;
            if (cast == null)
            {
                throw new InvalidOperationException();
            }
    
            message.Subject = $"Need consultation {cast.Name}";
            mail.Body = $@"Name:  {cast.Name}
                           Email: {cast.Email}
                           Phone: {cast.PhoneNumber}
                           Link:  {cast.BotLink}";
        }
    }
    

    You register those hydrators in your DI as named/keyed registrations where the name/key is full name of form type. So something like:

    this.AddSingleton<IMailHydrator, FeedBackFormHydrator>().Named(typeof(FeedBackForm).FullName);
    

    You change your method to:

    public async Task SendFormToAdminEmailAsync (IFormData form)
    {
        var fromAddress = _configuration["EmailCredentials:Email"];
        var fromPassword = _configuration["EmailCredentials:Password"];
        var toAddress = new MailAddress("[email protected]");
        var mail = new MailMessage(new MailAddress(fromAddress), toAddress);
    
        var hydrator = this.container.Resolve<IMailHydrator>(form.GetType().FullName);
        hydrator.Hydrate(mail, form);
        using (SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587))
        {
            smtp.Credentials = new NetworkCredential("[email protected]", fromPassword);
            smtp.EnableSsl = true;
    
            await smtp.SendMailAsync(mail);
        }
    }
    

    There may be some tweaking depending on your DI container.