/// <summary>
        /// Prepare paged queued email list model
        /// </summary>
        /// <param name="searchModel">Queued email search model</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the queued email list model
        /// </returns>
        public virtual async Task <QueuedEmailListModel> PrepareQueuedEmailListModelAsync(QueuedEmailSearchModel searchModel)
        {
            if (searchModel == null)
            {
                throw new ArgumentNullException(nameof(searchModel));
            }

            //get parameters to filter emails
            var startDateValue = !searchModel.SearchStartDate.HasValue ? null
                : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.SearchStartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync());
            var endDateValue = !searchModel.SearchEndDate.HasValue ? null
                : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.SearchEndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1);

            //get queued emails
            var queuedEmails = await _queuedEmailService.SearchEmailsAsync(fromEmail : searchModel.SearchFromEmail,
                                                                           toEmail : searchModel.SearchToEmail,
                                                                           createdFromUtc : startDateValue,
                                                                           createdToUtc : endDateValue,
                                                                           loadNotSentItemsOnly : searchModel.SearchLoadNotSent,
                                                                           loadOnlyItemsToBeSent : false,
                                                                           maxSendTries : searchModel.SearchMaxSentTries,
                                                                           loadNewest : true,
                                                                           pageIndex : searchModel.Page - 1, pageSize : searchModel.PageSize);

            //prepare list model
            var model = await new QueuedEmailListModel().PrepareToGridAsync(searchModel, queuedEmails, () =>
            {
                return(queuedEmails.SelectAwait(async queuedEmail =>
                {
                    //fill in model values from the entity
                    var queuedEmailModel = queuedEmail.ToModel <QueuedEmailModel>();

                    //little performance optimization: ensure that "Body" is not returned
                    queuedEmailModel.Body = string.Empty;

                    //convert dates to the user time
                    queuedEmailModel.CreatedOn = await _dateTimeHelper.ConvertToUserTimeAsync(queuedEmail.CreatedOnUtc, DateTimeKind.Utc);

                    //fill in additional values (not existing in the entity)
                    var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(queuedEmail.EmailAccountId);
                    queuedEmailModel.EmailAccountName = GetEmailAccountName(emailAccount);
                    queuedEmailModel.PriorityName = await _localizationService.GetLocalizedEnumAsync(queuedEmail.Priority);

                    if (queuedEmail.DontSendBeforeDateUtc.HasValue)
                    {
                        queuedEmailModel.DontSendBeforeDate = await _dateTimeHelper
                                                              .ConvertToUserTimeAsync(queuedEmail.DontSendBeforeDateUtc.Value, DateTimeKind.Utc);
                    }

                    if (queuedEmail.SentOnUtc.HasValue)
                    {
                        queuedEmailModel.SentOn = await _dateTimeHelper.ConvertToUserTimeAsync(queuedEmail.SentOnUtc.Value, DateTimeKind.Utc);
                    }

                    return queuedEmailModel;
                }));
            });

            return(model);
        }
Beispiel #2
0
        private async System.Threading.Tasks.Task SendAlertEmailAsync(int orderId, string exceptionMessage)
        {
            var failureEmail = _settings.FailureAlertEmail;

            if (!string.IsNullOrEmpty(failureEmail))
            {
                var defaultEmailAddress = await _emailAccountService.GetEmailAccountByIdAsync(
                    _emailAccountSettings.DefaultEmailAccountId
                    );

                var email = new QueuedEmail
                {
                    Priority              = QueuedEmailPriority.High,
                    From                  = defaultEmailAddress.Email,
                    FromName              = defaultEmailAddress.DisplayName,
                    To                    = failureEmail,
                    Subject               = $"ISAM Order Export Failed (#{orderId})",
                    Body                  = $"More information:\n\n{exceptionMessage}",
                    CreatedOnUtc          = DateTime.UtcNow,
                    EmailAccountId        = defaultEmailAddress.Id,
                    DontSendBeforeDateUtc = null
                };

                await _queuedEmailService.InsertQueuedEmailAsync(email);
            }
            else
            {
                await _logger.WarningAsync("No failure alert email provided, will not provide alert notification.");
            }
        }
        public async Task <IActionResult> DisplayContactUs(ContactUsModel model)
        {
            var resultModel = new ContactUsResultModel();

            if (_captchaSettings.Enabled)
            {
                var gCaptchaResponseValue = model.GRecaptchaResponse;

                if (StringValues.IsNullOrEmpty(gCaptchaResponseValue))
                {
                    return(BadRequest());
                }

                var response = _captchaHttpClient.ValidateCaptchaAsync(gCaptchaResponseValue).Result;
                if (!response.IsValid)
                {
                    return(BadRequest());
                }
            }

            var account = await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId);

            var ccEmails = new List <string>(_contactUsWidgetSettings.AdditionalEmails.Split(','));

            var toAddress = "";

            if (model.SelectedStore == "Website")
            {
                toAddress = _settings.ContactUsEmail ?? "*****@*****.**";
            }
            else
            {
                var shop = _shopRepository.Table.Where(s => s.Name == model.SelectedStore).FirstOrDefault();
                toAddress = _shopAbcRepository.Table.Where(sabc => sabc.ShopId == shop.Id).FirstOrDefault().AbcEmail;
                ccEmails.Add(_settings.ContactUsEmail);
            }

            var subject = "Customer " + model.Reason + "- " + model.SelectedStore + "/" + model.Name + "  " + model.PhoneNumber;

            var body = string.Format(
                @"A request has been submitted with an inquiry from the Contact us page. <br/><br/>

                Customer Name: {0} <br/>
                Customer Email: {1} <br/>
                Customer Phone Number: {2} <br/>
                Store Location: {3} <br/>
                Comments: {4}", model.Name ?? "", model.Email ?? "", model.PhoneNumber ?? "", model.SelectedStore ?? "", model.Comments ?? "");

            if (_settings.IsEmailSubmissionSkipped)
            {
                await _logger.WarningAsync($"AbcContactUs: Email submission skipped - body: {body}");
            }
            else
            {
                await _emailSender.SendEmailAsync(account, subject, body, account.Email, account.DisplayName, toAddress, "", replyToAddress : model.Email, cc : ccEmails);
            }

            return(Content(""));
        }
Beispiel #4
0
        /// <summary>
        /// moves old energy guides, product specs, and images to archive folders. Deletes pictures attached to deleted products
        /// </summary>
        /// <param name="backendConn">connection to the ISAM backend to check valid products</param>
        public async Task ArchiveProductContentAsync(IDbConnection backendConn)
        {
            var allowedItemNumbers = GetAllowedItemNumbers(backendConn);

            var archivedItemsSet        = new HashSet <string>();
            var ProcessedImageDirectory = $"{_importSettings.GetLocalPicturesDirectory()}";

            ArchiveFiles(allowedItemNumbers, _importSettings.GetEnergyGuidePdfPath(), GetFileNames(_importSettings.GetEnergyGuidePdfPath()), ref archivedItemsSet);
            ArchiveFiles(allowedItemNumbers, _importSettings.GetSpecificationPdfPath(), GetFileNames(_importSettings.GetSpecificationPdfPath()), ref archivedItemsSet);
            ArchiveFiles(allowedItemNumbers, ProcessedImageDirectory, GetFileNames(ProcessedImageDirectory, "*_large.*"),
                         ref archivedItemsSet, $"{_importSettings.GetLocalPicturesDirectory()}/Archive");

            //deleting old pictures from archived products
            await _nopDbContext.ExecuteNonQueryAsync(_deleteArchivedProductPictures);

            var account = await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId);

            var ccEmails = new List <string>();

            if (!string.IsNullOrEmpty(_importSettings.ArchiveTaskCCEmails))
            {
                ccEmails.AddRange(_importSettings.ArchiveTaskCCEmails.Split(','));
            }

            string body;
            bool   hasArchivedItems = archivedItemsSet.Any();

            if (hasArchivedItems)
            {
                body = "No items were archived";
            }
            else
            {
                body = "Files from the following item numbers were archived:";
                foreach (var itemNo in archivedItemsSet)
                {
                    body += $"<br/>{itemNo}";
                }
            }

            await _emailSender.SendEmailAsync(account, "Archive Task Complete", body, account.Email, account.DisplayName, "*****@*****.**", "", cc : ccEmails);

            if (hasArchivedItems)
            {
                await _logger.InformationAsync($"Archived items: {string.Join(",", archivedItemsSet)}");
            }
            else
            {
                await _logger.InformationAsync("No archived items.");
            }
        }
        /// <summary>
        /// Uninstall the plugin
        /// </summary>
        /// <returns>A task that represents the asynchronous operation</returns>
        public override async Task UninstallAsync()
        {
            //smtp accounts
            foreach (var store in await _storeService.GetAllStoresAsync())
            {
                var key            = $"{nameof(SendinblueSettings)}.{nameof(SendinblueSettings.EmailAccountId)}";
                var emailAccountId = await _settingService.GetSettingByKeyAsync <int>(key, storeId : store.Id, loadSharedValueIfNotFound : true);

                var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(emailAccountId);

                if (emailAccount != null)
                {
                    await _emailAccountService.DeleteEmailAccountAsync(emailAccount);
                }
            }

            //settings
            if (_widgetSettings.ActiveWidgetSystemNames.Contains(SendinblueDefaults.SystemName))
            {
                _widgetSettings.ActiveWidgetSystemNames.Remove(SendinblueDefaults.SystemName);
                await _settingService.SaveSettingAsync(_widgetSettings);
            }
            await _settingService.DeleteSettingAsync <SendinblueSettings>();

            //generic attributes
            foreach (var store in await _storeService.GetAllStoresAsync())
            {
                var messageTemplates = await _messageTemplateService.GetAllMessageTemplatesAsync(store.Id);

                foreach (var messageTemplate in messageTemplates)
                {
                    await _genericAttributeService.SaveAttributeAsync <int?>(messageTemplate, SendinblueDefaults.TemplateIdAttribute, null);
                }
            }

            //schedule task
            var task = await _scheduleTaskService.GetTaskByTypeAsync(SendinblueDefaults.SynchronizationTask);

            if (task != null)
            {
                await _scheduleTaskService.DeleteTaskAsync(task);
            }

            //locales
            await _localizationService.DeleteLocaleResourcesAsync("Plugins.Misc.Sendinblue");

            await base.UninstallAsync();
        }
        /// <summary>
        /// Executes a task
        /// </summary>
        public virtual async System.Threading.Tasks.Task ExecuteAsync()
        {
            var maxTries     = 3;
            var queuedEmails = await _queuedEmailService.SearchEmailsAsync(null, null, null, null,
                                                                           true, true, maxTries, false, 0, 500);

            foreach (var queuedEmail in queuedEmails)
            {
                var bcc = string.IsNullOrWhiteSpace(queuedEmail.Bcc)
                            ? null
                            : queuedEmail.Bcc.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                var cc = string.IsNullOrWhiteSpace(queuedEmail.CC)
                            ? null
                            : queuedEmail.CC.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                try
                {
                    await _emailSender.SendEmailAsync(await _emailAccountService.GetEmailAccountByIdAsync(queuedEmail.EmailAccountId),
                                                      queuedEmail.Subject,
                                                      queuedEmail.Body,
                                                      queuedEmail.From,
                                                      queuedEmail.FromName,
                                                      queuedEmail.To,
                                                      queuedEmail.ToName,
                                                      queuedEmail.ReplyTo,
                                                      queuedEmail.ReplyToName,
                                                      bcc,
                                                      cc,
                                                      queuedEmail.AttachmentFilePath,
                                                      queuedEmail.AttachmentFileName,
                                                      queuedEmail.AttachedDownloadId);

                    queuedEmail.SentOnUtc = DateTime.UtcNow;
                }
                catch (Exception exc)
                {
                    await _logger.ErrorAsync($"Error sending e-mail. {exc.Message}", exc);
                }
                finally
                {
                    queuedEmail.SentTries += 1;
                    await _queuedEmailService.UpdateQueuedEmailAsync(queuedEmail);
                }
            }
        }
        /// <summary>
        /// Create a new SMTP client for a specific email account
        /// </summary>
        /// <param name="emailAccount">Email account to use. If null, then would be used EmailAccount by default</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the an SMTP client that can be used to send email messages
        /// </returns>
        public virtual async Task <SmtpClient> BuildAsync(EmailAccount emailAccount = null)
        {
            if (emailAccount is null)
            {
                emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId)
                               ?? throw new NopException("Email account could not be loaded");
            }

            var client = new SmtpClient {
                ServerCertificateValidationCallback = ValidateServerCertificate
            };

            try
            {
                await client.ConnectAsync(
                    emailAccount.Host,
                    emailAccount.Port,
                    emailAccount.EnableSsl?SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTlsWhenAvailable);

                if (emailAccount.UseDefaultCredentials)
                {
                    await client.AuthenticateAsync(CredentialCache.DefaultNetworkCredentials);
                }
                else if (!string.IsNullOrWhiteSpace(emailAccount.Username))
                {
                    await client.AuthenticateAsync(new NetworkCredential(emailAccount.Username, emailAccount.Password));
                }

                return(client);
            }
            catch (Exception ex)
            {
                client.Dispose();
                throw new NopException(ex.Message, ex);
            }
        }
        /// <returns>A task that represents the asynchronous operation</returns>
        public virtual async Task <IActionResult> MarkAsDefaultEmail(int id)
        {
            if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageEmailAccounts))
            {
                return(AccessDeniedView());
            }

            var defaultEmailAccount = await _emailAccountService.GetEmailAccountByIdAsync(id);

            if (defaultEmailAccount == null)
            {
                return(RedirectToAction("List"));
            }

            _emailAccountSettings.DefaultEmailAccountId = defaultEmailAccount.Id;
            await _settingService.SaveSettingAsync(_emailAccountSettings);

            return(RedirectToAction("List"));
        }
Beispiel #9
0
        /// <summary>
        /// Prepare SendinblueModel
        /// </summary>
        /// <param name="model">Model</param>
        private async Task PrepareModelAsync(ConfigurationModel model)
        {
            //load settings for active store scope
            var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();

            var sendinblueSettings = await _settingService.LoadSettingAsync <SendinblueSettings>(storeId);

            //whether plugin is configured
            if (string.IsNullOrEmpty(sendinblueSettings.ApiKey))
            {
                return;
            }

            //prepare common properties
            model.ActiveStoreScopeConfiguration = storeId;
            model.ApiKey                 = sendinblueSettings.ApiKey;
            model.ListId                 = sendinblueSettings.ListId;
            model.SmtpKey                = sendinblueSettings.SmtpKey;
            model.SenderId               = sendinblueSettings.SenderId;
            model.UseSmsNotifications    = sendinblueSettings.UseSmsNotifications;
            model.SmsSenderName          = sendinblueSettings.SmsSenderName;
            model.StoreOwnerPhoneNumber  = sendinblueSettings.StoreOwnerPhoneNumber;
            model.UseMarketingAutomation = sendinblueSettings.UseMarketingAutomation;
            model.TrackingScript         = sendinblueSettings.TrackingScript;

            model.HideGeneralBlock = await _genericAttributeService.GetAttributeAsync <bool>(await _workContext.GetCurrentCustomerAsync(), SendinblueDefaults.HideGeneralBlock);

            model.HideSynchronizationBlock = await _genericAttributeService.GetAttributeAsync <bool>(await _workContext.GetCurrentCustomerAsync(), SendinblueDefaults.HideSynchronizationBlock);

            model.HideTransactionalBlock = await _genericAttributeService.GetAttributeAsync <bool>(await _workContext.GetCurrentCustomerAsync(), SendinblueDefaults.HideTransactionalBlock);

            model.HideSmsBlock = await _genericAttributeService.GetAttributeAsync <bool>(await _workContext.GetCurrentCustomerAsync(), SendinblueDefaults.HideSmsBlock);

            model.HideMarketingAutomationBlock = await _genericAttributeService.GetAttributeAsync <bool>(await _workContext.GetCurrentCustomerAsync(), SendinblueDefaults.HideMarketingAutomationBlock);

            //prepare nested search models
            model.MessageTemplateSearchModel.SetGridPageSize();
            model.SmsSearchModel.SetGridPageSize();

            //prepare add SMS model
            model.AddSms.AvailablePhoneTypes.Add(new SelectListItem(await _localizationService.GetResourceAsync("Plugins.Misc.Sendinblue.MyPhone"), "0"));
            model.AddSms.AvailablePhoneTypes.Add(new SelectListItem(await _localizationService.GetResourceAsync("Plugins.Misc.Sendinblue.CustomerPhone"), "1"));
            model.AddSms.AvailablePhoneTypes.Add(new SelectListItem(await _localizationService.GetResourceAsync("Plugins.Misc.Sendinblue.BillingAddressPhone"), "2"));
            model.AddSms.DefaultSelectedPhoneTypeId = model.AddSms.AvailablePhoneTypes.First().Value;

            var stores = await _storeService.GetAllStoresAsync();

            var messageTemplates = await _messageTemplateService.GetAllMessageTemplatesAsync(storeId);

            model.AddSms.AvailableMessages = await messageTemplates.SelectAwait(async messageTemplate =>
            {
                var name = messageTemplate.Name;
                if (storeId == 0 && messageTemplate.LimitedToStores)
                {
                    var storeIds   = await _storeMappingService.GetStoresIdsWithAccessAsync(messageTemplate);
                    var storeNames = stores.Where(store => storeIds.Contains(store.Id)).Select(store => store.Name);
                    name           = $"{name} ({string.Join(',', storeNames)})";
                }

                return(new SelectListItem(name, messageTemplate.Id.ToString()));
            }).ToListAsync();

            var defaultSelectedMessage = model.AddSms.AvailableMessages.FirstOrDefault();

            model.AddSms.DefaultSelectedMessageId = defaultSelectedMessage?.Value ?? "0";

            //check whether email account exists
            if (sendinblueSettings.UseSmtp && await _emailAccountService.GetEmailAccountByIdAsync(sendinblueSettings.EmailAccountId) != null)
            {
                model.UseSmtp = sendinblueSettings.UseSmtp;
            }

            //get account info
            var(accountInfo, marketingAutomationEnabled, maKey, accountErrors) = await _sendinblueEmailManager.GetAccountInfoAsync();

            model.AccountInfo                 = accountInfo;
            model.MarketingAutomationKey      = maKey;
            model.MarketingAutomationDisabled = !marketingAutomationEnabled;
            if (!string.IsNullOrEmpty(accountErrors))
            {
                _notificationService.ErrorNotification($"{SendinblueDefaults.NotificationMessage} {accountErrors}");
            }

            //prepare overridable settings
            if (storeId > 0)
            {
                model.ListId_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.ListId, storeId);

                model.UseSmtp_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.UseSmtp, storeId);

                model.SenderId_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.SenderId, storeId);

                model.UseSmsNotifications_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.UseSmsNotifications, storeId);

                model.SmsSenderName_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.SmsSenderName, storeId);

                model.UseMarketingAutomation_OverrideForStore = await _settingService.SettingExistsAsync(sendinblueSettings, settings => settings.UseMarketingAutomation, storeId);
            }

            //check SMTP status
            var(smtpEnabled, smtpErrors) = await _sendinblueEmailManager.SmtpIsEnabledAsync();

            if (!string.IsNullOrEmpty(smtpErrors))
            {
                _notificationService.ErrorNotification($"{SendinblueDefaults.NotificationMessage} {smtpErrors}");
            }

            //get available contact lists to synchronize
            var(lists, listsErrors) = await _sendinblueEmailManager.GetListsAsync();

            model.AvailableLists = lists.Select(list => new SelectListItem(list.Name, list.Id)).ToList();
            model.AvailableLists.Insert(0, new SelectListItem("Select list", "0"));
            if (!string.IsNullOrEmpty(listsErrors))
            {
                _notificationService.ErrorNotification($"{SendinblueDefaults.NotificationMessage} {listsErrors}");
            }

            //get available senders of emails from account
            var(senders, sendersErrors) = await _sendinblueEmailManager.GetSendersAsync();

            model.AvailableSenders = senders.Select(list => new SelectListItem(list.Name, list.Id)).ToList();
            model.AvailableSenders.Insert(0, new SelectListItem("Select sender", "0"));
            if (!string.IsNullOrEmpty(sendersErrors))
            {
                _notificationService.ErrorNotification($"{SendinblueDefaults.NotificationMessage} {sendersErrors}");
            }

            //get allowed tokens
            model.AllowedTokens = string.Join(", ", await _messageTokenProvider.GetListOfAllowedTokensAsync());

            //create attributes in account
            var attributesErrors = await _sendinblueEmailManager.PrepareAttributesAsync();

            if (!string.IsNullOrEmpty(attributesErrors))
            {
                _notificationService.ErrorNotification($"{SendinblueDefaults.NotificationMessage} {attributesErrors}");
            }
        }
        /// <summary>
        /// Send email notification by message template
        /// </summary>
        /// <param name="messageTemplate">Message template</param>
        /// <param name="emailAccount">Email account</param>
        /// <param name="tokens">Tokens</param>
        /// <param name="toEmailAddress">Recipient email address</param>
        /// <param name="toName">Recipient name</param>
        /// <param name="attachmentFilePath">Attachment file path</param>
        /// <param name="attachmentFileName">Attachment file name</param>
        /// <param name="replyToEmailAddress">"Reply to" email</param>
        /// <param name="replyToName">"Reply to" name</param>
        /// <param name="fromEmail">Sender email. If specified, then it overrides passed "emailAccount" details</param>
        /// <param name="fromName">Sender name. If specified, then it overrides passed "emailAccount" details</param>
        /// <param name="subject">Subject. If specified, then it overrides subject of a message template</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the queued email identifier
        /// </returns>
        private async Task <int?> SendEmailNotificationAsync(MessageTemplate messageTemplate, EmailAccount emailAccount, IEnumerable <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)
        {
            //get plugin settings
            var storeId            = (int?)tokens.FirstOrDefault(token => token.Key == "Store.Id")?.Value;
            var sendinblueSettings = await _settingService.LoadSettingAsync <SendinblueSettings>(storeId ?? 0);

            //ensure email notifications enabled
            if (!sendinblueSettings.UseSmtp)
            {
                return(null);
            }

            //whether to send email by the passed message template
            var templateId = await _genericAttributeService.GetAttributeAsync <int?>(messageTemplate, SendinblueDefaults.TemplateIdAttribute);

            var sendEmailForThisMessageTemplate = templateId.HasValue;

            if (!sendEmailForThisMessageTemplate)
            {
                return(null);
            }

            //get the specified email account from settings
            emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(sendinblueSettings.EmailAccountId) ?? emailAccount;

            //get an email from the template
            var email = await _sendinblueEmailManager.GetQueuedEmailFromTemplateAsync(templateId.Value)
                        ?? throw new NopException($"There is no template with id {templateId}");

            //replace body and subject tokens
            if (string.IsNullOrEmpty(subject))
            {
                subject = email.Subject;
            }
            if (!string.IsNullOrEmpty(subject))
            {
                email.Subject = _tokenizer.Replace(subject, tokens, false);
            }
            if (!string.IsNullOrEmpty(email.Body))
            {
                email.Body = _tokenizer.Replace(email.Body, tokens, true);
            }

            //set email parameters
            email.Priority              = QueuedEmailPriority.High;
            email.From                  = !string.IsNullOrEmpty(fromEmail) ? fromEmail : email.From;
            email.FromName              = !string.IsNullOrEmpty(fromName) ? fromName : email.FromName;
            email.To                    = toEmailAddress;
            email.ToName                = CommonHelper.EnsureMaximumLength(toName, 300);
            email.ReplyTo               = replyToEmailAddress;
            email.ReplyToName           = replyToName;
            email.CC                    = string.Empty;
            email.Bcc                   = messageTemplate.BccEmailAddresses;
            email.AttachmentFilePath    = attachmentFilePath;
            email.AttachmentFileName    = attachmentFileName;
            email.AttachedDownloadId    = messageTemplate.AttachedDownloadId;
            email.CreatedOnUtc          = DateTime.UtcNow;
            email.EmailAccountId        = emailAccount.Id;
            email.DontSendBeforeDateUtc = messageTemplate.DelayBeforeSend.HasValue
                ? (DateTime?)(DateTime.UtcNow + TimeSpan.FromHours(messageTemplate.DelayPeriod.ToHours(messageTemplate.DelayBeforeSend.Value)))
                : null;

            //queue email
            await _queuedEmailService.InsertQueuedEmailAsync(email);

            return(email.Id);
        }
 protected virtual async Task <EmailAccount> GetEmailAccountAsync(int emailAccountId)
 {
     return(await _emailAccountService.GetEmailAccountByIdAsync(emailAccountId)
            ?? await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId)
            ?? throw new NopException("Email account could not be loaded"));
 }