Sending emails from a plugin

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
6 anos atrás
Hi

I'm working on a plugin that will require an email to be sent. This email will require a new message template. I was hoping nop had a generic means for sending email however IWorkflowMessageService defines specific emails. I realise i could copy that class/interface to my plugin code and add my new methods and register my type with autofac but I was hoping to avoid going that route if possible.

Anyone else come up with a solution?


Thanks
6 anos atrás
You can manually insert QueuedEmail record in database (use "InsertQueuedEmail" method of IWorkflowMessageService)
5 anos atrás
seanrock wrote:
Hi

I'm working on a plugin that will require an email to be sent. This email will require a new message template. I was hoping nop had a generic means for sending email however IWorkflowMessageService defines specific emails. I realise i could copy that class/interface to my plugin code and add my new methods and register my type with autofac but I was hoping to avoid going that route if possible.

Anyone else come up with a solution?


Thanks


@seanrock. Did you find a way to achieve it?
1 ano atrás
Hello,

I have a plugin that is a custom form. After the customer fills in he will receive a personalized email as an example "Thank you for your registration". Can you help me with this?

here's what i did:

Interaface :

using Nop.Core.Domain.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nop.Plugin.Misc.EasyComTecGeneralRegister.Interface
{
    public interface IEnviarEmail
    {
        Task SendEmailAsync(EmailAccount emailAccount, string subject, string body,
            string fromAddress, string fromName, string toAddress, string toName
            );
    }
}


Service

using MimeKit;
using MimeKit.Text;
using Nop.Core;
using Nop.Core.Domain.Media;
using Nop.Core.Domain.Messages;
using Nop.Core.Infrastructure;
using Nop.Plugin.Misc.EasyComTecGeneralRegister.Interface;
using Nop.Services.Media;
using Nop.Services.Messages;
using Nop.Web.Framework.Models.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nop.Plugin.Misc.EasyComTecGeneralRegister.Services
{
    public class EnviarEmail : IEnviarEmail
    {
        private readonly ISmtpBuilder _smtpBuilder;
        private readonly IWorkContext _workContext;
        private readonly INopFileProvider _fileProvider;
        private readonly IDownloadService _downloadService;
        private readonly EmailAccountSettings _emailAccountSettings;
        private readonly IEmailAccountService _emailAccountService;
        public EnviarEmail(EmailAccountSettings emailAccountSettings,
            IEmailAccountService emailAccountService, IWorkContext workContext, IDownloadService downloadService, INopFileProvider fileProvider, ISmtpBuilder smtpBuilder)
        {
            _smtpBuilder = smtpBuilder;
            _workContext = workContext;
            _fileProvider = fileProvider;
            _downloadService = downloadService;
            _emailAccountSettings = emailAccountSettings;
            _emailAccountService = emailAccountService;
        }
        public async Task SendEmailAsync(EmailAccount emailAccount, string subject, string body,
            string fromAddress, string fromName, string toAddress, string toName)
        {
            var message = new MimeMessage();

            message.From.Add(new MailboxAddress(fromName, fromAddress));
            message.To.Add(new MailboxAddress(toName, toAddress));                      
            //content
            message.Subject = subject;
            //headers
            
            var multipart = new Multipart("mixed")
            {
                new TextPart(TextFormat.Html) { Text = body }
            };                                  
            
            message.Body = multipart;
            var emailAccounts = (await _emailAccountService.GetAllEmailAccountsAsync());
            var email = new EmailAccount
            {
                Email = emailAccounts.FirstOrDefault().Email,
                Host = emailAccounts.FirstOrDefault().Host,
                Port = emailAccounts.FirstOrDefault().Port,
                Password = emailAccounts.FirstOrDefault().Password,
                DisplayName = emailAccounts.FirstOrDefault().DisplayName,
                UseDefaultCredentials = emailAccounts.FirstOrDefault().UseDefaultCredentials,
                Username = emailAccounts.FirstOrDefault().Username,
                Id = emailAccounts.FirstOrDefault().Id,
            };
            //send email
            using var smtpClient = await _smtpBuilder.BuildAsync(email);
            await smtpClient.SendAsync(message);
            await smtpClient.DisconnectAsync(true);    
        }
    }
}
1 ano atrás
fsander wrote:
Hello,
I have a plugin that is a custom form. After the customer fills in he will receive a personalized email as an example "Thank you for your registration". Can you help me with this?

why isn't you using default project code to send email?
for example, i am sending one email to customer and one email to store owner from plugin from custom contact us form submit
1. first insert one message template while install the plugin

/// <summary>
        /// Install the plugin
        /// </summary>
        /// <returns>A task that represents the asynchronous operation</returns>
        public override async Task InstallAsync()
        {
            var eaGeneral = _emailAccountRepository.Table.FirstOrDefault();
            if (eaGeneral == null)
                throw new Exception("Default email account cannot be loaded");
            //settings
            var settings = new ContactCallUsSettings
            {
                EnableCallUs = true,
                EnableContactUs = true
            };
            await _settingService.SaveSettingAsync(settings);

            //store owner email template
            var templates = (await _messageTemplateService.GetMessageTemplatesByNameAsync(ContactCallUsDefaults.StoreOwnerEmailTemplateSystemName)).FirstOrDefault();
            var template = new MessageTemplate
            {
                Name = ContactCallUsDefaults.StoreOwnerEmailTemplateSystemName,
                Subject = "%Message.Subject%",
                Body = $"<p>Product Name: %ContactCallUs.ProductName%<br/>Sku: %ContactCallUs.Sku%<br/>Name: %ContactCallUs.Name%<br/>Company Name: %ContactCallUs.CompanyName%" +
                $"<br/>Phone: %ContactCallUs.Phone%<br/>Email: %ContactCallUs.Email%<br/>Comment: %ContactCallUs.Message%<br/></p>{Environment.NewLine}",
                IsActive = true,
                EmailAccountId = eaGeneral.Id
            };
            if (templates == null)
                await _messageTemplateService.InsertMessageTemplateAsync(template);
            else
                throw new NopException("Message Template Already Exist");

            //customer email template
            templates = (await _messageTemplateService.GetMessageTemplatesByNameAsync(ContactCallUsDefaults.CustomerEmailTemplateSystemName)).FirstOrDefault();
            template = new MessageTemplate
            {
                Name = ContactCallUsDefaults.CustomerEmailTemplateSystemName,
                Subject = "%Message.Subject%",
                Body = $"Your request is submitted for <br/><p>Product Name: %ContactCallUs.ProductName%<br/>Sku: %ContactCallUs.Sku%</p>{Environment.NewLine}",
                IsActive = true,
                EmailAccountId = eaGeneral.Id
            };
            if (templates == null)
                await _messageTemplateService.InsertMessageTemplateAsync(template);
            else
                throw new NopException("Message Template Already Exist");
//.... your more insertion
   await base.InstallAsync();
        }

2.  create your service that contain mail sending code

#region mail

        public virtual async Task<IList<int>> SendContactCallUsMessageToStoreOwnerAsync(int languageId, string senderEmail,
        string senderName, string subject, ContactCallUsRecordsModel callbackModel)
        {
            var model = callbackModel.ToEntity<ContactCallUsRecords>();
            var store = await _storeContext.GetCurrentStoreAsync();
            languageId = await EnsureLanguageIsActiveAsync(languageId, store.Id);

            var product = await _productService.GetProductByIdAsync(callbackModel.ProductId);

            var messageTemplates = await GetActiveMessageTemplatesAsync(ContactCallUsDefaults.StoreOwnerEmailTemplateSystemName, store.Id);
            if (!messageTemplates.Any())
                return new List<int>();

            //tokens
            var commonTokens = new List<Token>
            {
                new Token("ContactUs.SenderEmail", senderEmail),
                new Token("ContactUs.SenderName", senderName),
                new Token("Message.Subject", subject, true),
                new Token("ContactCallUs.ProductName", product.Name),
                new Token("ContactCallUs.Sku", product.Sku),
                new Token("ContactCallUs.Name", callbackModel.Name ),
                new Token("ContactCallUs.Phone", callbackModel.Phone),
                new Token("ContactCallUs.CompanyName", callbackModel.CompanyName),
                new Token("ContactCallUs.Email", callbackModel.Email),
                new Token("ContactCallUs.Message", callbackModel.Message)
            };

            return await messageTemplates.SelectAwait(async messageTemplate =>
            {
                //email account
                var emailAccount = await GetEmailAccountOfMessageTemplateAsync(messageTemplate, languageId);

                var toEmail = emailAccount.Email;
                var toName = emailAccount.DisplayName;

                return await SendNotificationAsync(messageTemplate, emailAccount, languageId, commonTokens, toEmail, toName,
                    fromEmail: senderEmail,
                    fromName: senderName,
                    subject: subject,
                    replyToEmailAddress: senderEmail,
                    replyToName: senderName);
            }).ToListAsync();
        }

        public virtual async Task<IList<int>> SendContactCallUsMessageToCustomerAsync(int languageId, string senderEmail,
        string senderName, string subject, ContactCallUsRecordsModel callbackModel)
        {
            var model = callbackModel.ToEntity<ContactCallUsRecords>();
            var store = await _storeContext.GetCurrentStoreAsync();
            languageId = await EnsureLanguageIsActiveAsync(languageId, store.Id);

            var product = await _productService.GetProductByIdAsync(callbackModel.ProductId);

            var messageTemplates = await GetActiveMessageTemplatesAsync(ContactCallUsDefaults.CustomerEmailTemplateSystemName, store.Id);
            if (!messageTemplates.Any())
                return new List<int>();

            //tokens
            var commonTokens = new List<Token>
            {
                new Token("ContactUs.SenderEmail", senderEmail),
                new Token("ContactUs.SenderName", senderName),
                new Token("Message.Subject", subject, true),
                new Token("ContactCallUs.ProductName", product.Name),
                new Token("ContactCallUs.Sku", product.Sku),
                new Token("ContactCallUs.Name", callbackModel.Name ),
                new Token("ContactCallUs.Phone", callbackModel.Phone),
                new Token("ContactCallUs.CompanyName", callbackModel.CompanyName),
                new Token("ContactCallUs.Email", callbackModel.Email),
                new Token("ContactCallUs.Message", callbackModel.Message)
            };

            return await messageTemplates.SelectAwait(async messageTemplate =>
            {
                //email account
                var emailAccount = await GetEmailAccountOfMessageTemplateAsync(messageTemplate, languageId);

                return await SendNotificationAsync(messageTemplate, emailAccount, languageId, commonTokens, senderEmail, senderName,
                    fromEmail: emailAccount.Email,
                    fromName: emailAccount.DisplayName,
                    subject: subject,
                    replyToEmailAddress: emailAccount.Email,
                    replyToName: emailAccount.DisplayName);
            }).ToListAsync();
        }

        public virtual async Task<int> EnsureLanguageIsActiveAsync(int languageId, int storeId)
        {
            //load language by specified ID
            var language = await _languageService.GetLanguageByIdAsync(languageId);

            if (language == null || !language.Published)
            {
                //load any language from the specified store
                language = (await _languageService.GetAllLanguagesAsync(storeId: storeId)).FirstOrDefault();
            }

            if (language == null || !language.Published)
            {
                //load any language
                language = (await _languageService.GetAllLanguagesAsync()).FirstOrDefault();
            }

            if (language == null)
                throw new Exception("No active language could be loaded");

            return language.Id;
        }

        public virtual async Task<EmailAccount> GetEmailAccountOfMessageTemplateAsync(MessageTemplate messageTemplate, int languageId)
        {
            var emailAccountId = await _localizationService.GetLocalizedAsync(messageTemplate, mt => mt.EmailAccountId, languageId);
            //some 0 validation (for localizable "Email account" dropdownlist which saves 0 if "Standard" value is chosen)
            if (emailAccountId == 0)
                emailAccountId = messageTemplate.EmailAccountId;

            var emailAccount = (await _emailAccountService.GetEmailAccountByIdAsync(emailAccountId) ?? await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId)) ??
                               (await _emailAccountService.GetAllEmailAccountsAsync()).FirstOrDefault();
            return emailAccount;
        }

        public virtual async Task<IList<MessageTemplate>> GetActiveMessageTemplatesAsync(string messageTemplateName, int storeId)
        {
            //get message templates by the name
            var messageTemplates = await _messageTemplateService.GetMessageTemplatesByNameAsync(messageTemplateName, storeId);

            //no template found
            if (!messageTemplates?.Any() ?? true)
                return new List<MessageTemplate>();

            //filter active templates
            messageTemplates = messageTemplates.Where(messageTemplate => messageTemplate.IsActive).ToList();

            return messageTemplates;
        }

        public virtual async Task<int> SendNotificationAsync(MessageTemplate messageTemplate,
    EmailAccount emailAccount, int languageId, IList<Token> tokens,
    string toEmailAddress, string toName,
    string attachmentFilePath = null, string attachmentFileName = null,
    string replyToEmailAddress = null, string replyToName = null,
    string fromEmail = null, string fromName = null, string subject = null)
        {
            if (messageTemplate == null)
                throw new ArgumentNullException(nameof(messageTemplate));

            if (emailAccount == null)
                throw new ArgumentNullException(nameof(emailAccount));

            //retrieve localized message template data
            var bcc = await _localizationService.GetLocalizedAsync(messageTemplate, mt => mt.BccEmailAddresses, languageId);
            if (string.IsNullOrEmpty(subject))
                subject = await _localizationService.GetLocalizedAsync(messageTemplate, mt => mt.Subject, languageId);
            var body = await _localizationService.GetLocalizedAsync(messageTemplate, mt => mt.Body, languageId);

            //Replace subject and body tokens
            var subjectReplaced = _tokenizer.Replace(subject, tokens, false);
            var bodyReplaced = _tokenizer.Replace(body, tokens, true);

            //limit name length
            toName = CommonHelper.EnsureMaximumLength(toName, 300);

            var email = new QueuedEmail
            {
                Priority = QueuedEmailPriority.High,
                From = !string.IsNullOrEmpty(fromEmail) ? fromEmail : emailAccount.Email,
                FromName = !string.IsNullOrEmpty(fromName) ? fromName : emailAccount.DisplayName,
                To = toEmailAddress,
                ToName = toName,
                ReplyTo = replyToEmailAddress,
                ReplyToName = replyToName,
                CC = string.Empty,
                Bcc = bcc,
                Subject = subjectReplaced,
                Body = bodyReplaced,
                AttachmentFilePath = attachmentFilePath,
                AttachmentFileName = attachmentFileName,
                AttachedDownloadId = messageTemplate.AttachedDownloadId,
                CreatedOnUtc = DateTime.UtcNow,
                EmailAccountId = emailAccount.Id,
                DontSendBeforeDateUtc = !messageTemplate.DelayBeforeSend.HasValue ? null
                    : (DateTime?)(DateTime.UtcNow + TimeSpan.FromHours(messageTemplate.DelayPeriod.ToHours(messageTemplate.DelayBeforeSend.Value)))
            };

            await _queuedEmailService.InsertQueuedEmailAsync(email);
            return email.Id;
        }
        #endregion

3. make your controller to call service

[HttpPost]
        public virtual async Task<IActionResult> InsertContactCallUs(ContactCallUsRecordsModel contactCallUsModel)
        {
            if (ModelState.IsValid)
            {
                var model = contactCallUsModel.ToEntity<ContactCallUsRecords>();
                await _contactCallUsService.InsertRequestAsync(model);
                contactCallUsModel.Message = _contactCallUsService.FormatPostText(contactCallUsModel.Message);
                SendingMessage(contactCallUsModel);
            }
            return Ok(contactCallUsModel);
        }

        public virtual async void SendingMessage(ContactCallUsRecordsModel contactCallUsModel)
        {
            if (ModelState.IsValid)
            {
                var subject =
                    subject = await _localizationService.GetResourceAsync("OwnerEmail.Subject");
              
                //send email to store owner
                await _contactCallUsService.SendContactCallUsMessageToStoreOwnerAsync((await _workContext.GetWorkingLanguageAsync()).Id,
                    contactCallUsModel.Email.Trim(), contactCallUsModel.Name , subject, contactCallUsModel);

                //send email to customer
                await _contactCallUsService.SendContactCallUsMessageToCustomerAsync((await _workContext.GetWorkingLanguageAsync()).Id,
                   contactCallUsModel.Email.Trim(), contactCallUsModel.Name, await _localizationService.GetResourceAsync("CustomerMail.Subject"), contactCallUsModel);
            }
        }
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.