示例#1
0
        public bool SendEmailToMailingList(string subject, string message)
        {
            try
            {
                var msg = new SendGridMessage();

                msg.SetFrom(new EmailAddress("*****@*****.**", "Administrator"));
                var templateId = "1fde50ac-07f2-4f82-9f38-7194b77490a9";
                msg.TemplateId = templateId;

                Dictionary <string, string> substitutions = new Dictionary <string, string>()
                {
                    { "{subject}", subject },
                    { "{message}", message },
                };
                msg.AddSubstitutions(substitutions);

                List <EmailAddress> recpients = new List <EmailAddress>();
                foreach (var recipient in unitOfWork.MailingListRepo.GetAll())
                {
                    recpients.Add(new EmailAddress(recipient.EmailAddress));
                }
                msg.AddTos(recpients);

                Execute(client, msg).Wait();
            }
            catch (Exception ex)
            {
                unitOfWork.SetException(ex);
                return(false);
            }
            return(true);
        }
示例#2
0
        public bool SendVerificationEmail(string userEmail, string verificationCode)
        {
            try
            {
                var msg = new SendGridMessage();

                msg.SetFrom(new EmailAddress("*****@*****.**", "Administrator"));
                var templateId = "a942917c-bb5d-4d55-889d-bf6fff84446f";
                msg.TemplateId = templateId;

                Dictionary <string, string> substitutions = new Dictionary <string, string>()
                {
                    { "{verification_url}", "http://localhost:20346/Account/Register" },
                    { "{verification_code}", verificationCode },
                };

                msg.AddSubstitutions(substitutions);
                msg.AddTo(userEmail);

                Execute(client, msg).Wait();
            }
            catch (Exception ex)
            {
                unitOfWork.SetException(ex);
                return(false);
            }
            return(true);
        }
示例#3
0
        /// <summary>
        /// The CreateMessage
        /// </summary>
        /// <param name="type">The <see cref="NotificationType"/></param>
        /// <param name="model">The <see cref="NotificationRequestModel"/></param>
        /// <returns>The <see cref="SendGridMessage"/></returns>
        public SendGridMessage CreateMessage(NotificationType type, NotificationRequestModel model)
        {
            try
            {
                var mailMessage = new SendGridMessage();
                mailMessage.AddTo(model.DefaultDestination);
                mailMessage.SetFrom(new EmailAddress(Options.FromAddress, Options.FromDisplayName));
                mailMessage.SetSubject(model.DefaultSubject);
                mailMessage.AddContent(MimeType.Html, model.DefaultContent);

                var template = Options.Templates?.FirstOrDefault(c => c.Type == type);

                if (template != null)
                {
                    mailMessage.AddSubstitutions(model.Tokens);
                    if (!string.IsNullOrEmpty(template.Id))
                    {
                        mailMessage.SetTemplateId(template.Id);
                    }
                }

                return(mailMessage);
            }
            catch (Exception ex)
            {
                throw new FormatException($"Failed to construct mail message", ex);
            }
        }
示例#4
0
        static async void SendEmail(CaptchaMessage message)
        {
            var            apiKey  = "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";
            SendGridClient SClient = new SendGridClient(apiKey);

            try
            {
                var msg = new SendGridMessage()
                {
                    From = new EmailAddress("*****@*****.**", "Mailroom Service")
                };
                msg.SetTemplateId("9cba370f-5cf1-4a44-b73a-c7c2fe6e22c3");

                msg.AddTo(message.Alias + "@microsoft.com");

                msg.AddSubstitutions(new Dictionary <string, string>()
                {
                    { "-alias-", message.Alias },
                    { "-captcha-", message.Captcha }
                });

                await SClient.SendEmailAsync(msg);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }
        }
示例#5
0
        /// <summary>
        /// Send multiple emails to multiple recipients.
        /// </summary>
        /// <param name="from">An email object that may contain the recipient’s name, but must always contain the sender’s email.</param>
        /// <param name="tos">A list of email objects that may contain the recipient’s name, but must always contain the recipient’s email.</param>
        /// <param name="subjects">The subject of your email. This may be overridden by SetGlobalSubject().</param>
        /// <param name="plainTextContent">The text/plain content of the email body.</param>
        /// <param name="htmlContent">The text/html content of the email body.</param>
        /// <param name="substitutions">Substitution key/values to customize the content for each email.</param>
        /// <returns>A SendGridMessage object.</returns>
        public static SendGridMessage CreateMultipleEmailsToMultipleRecipients(
            EmailAddress from,
            List <EmailAddress> tos,
            List <string> subjects,
            string plainTextContent,
            string htmlContent,
            List <Dictionary <string, string> > substitutions)
        {
            var msg = new SendGridMessage();

            msg.SetFrom(from);
            if (!string.IsNullOrEmpty(plainTextContent))
            {
                msg.AddContent(MimeType.Text, plainTextContent);
            }

            if (!string.IsNullOrEmpty(htmlContent))
            {
                msg.AddContent(MimeType.Html, htmlContent);
            }

            for (var i = 0; i < tos.Count; i++)
            {
                msg.AddTo(tos[i], i);
                msg.SetSubject(subjects[i], i);
                msg.AddSubstitutions(substitutions[i], i);
            }

            return(msg);
        }
示例#6
0
        public async Task SendEmailAsync(MailMessage message)
        {
            var sendGridMessage = new SendGridMessage
            {
                Subject          = message.Subject,
                From             = new EmailAddress(_globalSettings.Mail.ReplyToEmail, _globalSettings.SiteName),
                HtmlContent      = message.HtmlContent,
                PlainTextContent = message.TextContent
            };

            sendGridMessage.SetClickTracking(true, false);
            sendGridMessage.SetOpenTracking(true, null);
            sendGridMessage.AddTos(message.ToEmails.Select(e => new EmailAddress(e)).ToList());
            if (message.BccEmails?.Any() ?? false)
            {
                sendGridMessage.AddBccs(message.BccEmails.Select(e => new EmailAddress(e)).ToList());
            }

            if (message.MetaData?.ContainsKey("SendGridTemplateId") ?? false)
            {
                sendGridMessage.HtmlContent      = " ";
                sendGridMessage.PlainTextContent = " ";
                sendGridMessage.TemplateId       = message.MetaData["SendGridTemplateId"].ToString();
            }

            if (message.MetaData?.ContainsKey("SendGridSubstitutions") ?? false)
            {
                var subs = message.MetaData["SendGridSubstitutions"] as Dictionary <string, string>;
                sendGridMessage.AddSubstitutions(subs);
            }

            var cats = new List <string> {
                "ByteGarden Server"
            };

            if (!string.IsNullOrWhiteSpace(message.Category))
            {
                cats.Add(message.Category);
            }
            sendGridMessage.AddCategories(cats);

            if (message.MetaData?.ContainsKey("SendGridBypassListManagement") ?? false)
            {
                var bypass = message.MetaData["SendGridBypassListManagement"] as bool?;
                sendGridMessage.SetBypassListManagement(bypass.GetValueOrDefault(false));
            }

            try
            {
                await SendAsync(sendGridMessage, false);
            }
            catch (HttpRequestException)
            {
                await SendAsync(sendGridMessage, true);
            }
            catch (WebException)
            {
                await SendAsync(sendGridMessage, true);
            }
        }
示例#7
0
        public async Task ForgotPassword(UserEmail model)
        {
            string tempPassword = _passwordService. //protected
                                  string salt = BCrypt.BCryptHelper.GenerateSalt();
            string hashedPassword = BCrypt.BCryptHelper.HashPassword(tempPassword, salt);

            _passwordService.Update(model.EmailAddress, hashedPassword);

            ForgotPassword email = new ForgotPassword();
            var            msg   = new SendGridMessage()
            {
                From        = new EmailAddress(_config.Email, _config.Sender),
                Subject     = email.Subject,
                HtmlContent = email.HtmlContent
            };
            Dictionary <string, string> subs = new Dictionary <string, string>
            {
                { "-subject-", "Forgot Password" },
                { "-tempPassword-", tempPassword },
                { "-siteUrl-", _siteConfig.SiteUrl }
            };

            msg.AddSubstitutions(subs);
            msg.AddTo(new EmailAddress(model.EmailAddress, email.Recipient));
            await Send(msg);
        }
 private void AddSubstitutionsToEmailMessage(
     SendGridMessage emailMessage,
     IDictionary <string, string> substitutions)
 {
     if (substitutions != null)
     {
         var substitutionsDict = new Dictionary <string, string>(substitutions);
         emailMessage.AddSubstitutions(substitutionsDict);
     }
 }
示例#9
0
        public async Task SendEmailAsync(EmailTemplate template)
        {
            var message = new SendGridMessage();

            message.SetFrom(new EmailAddress(_senderAddress, _senderName));
            message.AddTo(template.To);
            message.SetTemplateId(template.TemplateId);
            message.AddSubstitutions(template.SendGridSubstitutions.ToDictionary(k => k.Key, v => v.Value));

            await Execute(message);
        }
示例#10
0
        public async Task SendEmailAsync(EmailTemplate template)
        {
            SendGridMessage message = new SendGridMessage();

            message.SetFrom(_senderAddress);
            message.AddTo(template.To);
            message.SetTemplateId(template.TemplateId);
            message.AddSubstitutions(template.SendGridSubstitutions.ToDictionary(k => k.Key, v => v.Value));

            await Dispatch(message);
        }
示例#11
0
        public async Task SendEmailAsync(EmailTemplate template)
        {
            var message = new SendGridMessage();

            message.SetFrom(new EmailAddress("*****@*****.**", "RCM Email Service"));
            message.AddTo(template.To);
            message.SetTemplateId(template.TemplateId);
            message.AddSubstitutions(template.SendGridSubstitutions.ToDictionary(k => k.Key, v => v.Value));

            await Execute(message);
        }
示例#12
0
        private async Task <Response> SendTemplateEmail(EmailAddress recipient, string templateId, Dictionary <string, string> substitutions)
        {
            var client = new SendGridClient(ConfigurationHelper.SendGrid_ApiKey);
            var msg    = new SendGridMessage();

            msg.SetFrom(new EmailAddress(Constants.SendGrid_RegisterInternalEmail, Constants.SendGrid_RegisterEmailSubject));

            var recipients = new List <EmailAddress> {
                recipient
            };

            msg.AddTos(recipients);

            msg.AddSubstitutions(substitutions);
            msg.TemplateId = templateId;

            return(await client.SendEmailAsync(msg));
        }
示例#13
0
        public bool SendAccountInviteEmail(AccountInviteModel invite)
        {
            try
            {
                var msg        = new SendGridMessage();
                var templateId = "70cd6b26-44e7-4b62-b76b-db2c564e24ba";

                msg.TemplateId = templateId;

                AccountModel sender = unitOfWork.AccountRepo.Get(invite.SentByID);
                msg.SetFrom(new EmailAddress(sender.Email, sender.GetFullName()));

                Dictionary <string, string> substitutions = new Dictionary <string, string>()
                {
                    { "{sender_name}", sender.GetFullName().ToString() },
                    { "{account_creation_url}", "http://localhost:20346/Account/Register" }
                };

                msg.AddSubstitutions(substitutions);

                var recepiants = new List <EmailAddress>()
                {
                    new EmailAddress(invite.SentToEmail)
                };

                msg.AddTos(recepiants);

                msg.SetClickTracking(true, false);

                //string subject = "You have been invited to create an account on Victorious by " + sender.GetFullName();
                //msg.SetSubject(subject);

                //msg.AddContent(MimeType.Html, "<p> Visit {insert URL here}" + invite.AccountInviteCode + " to create your account </p>");


                Execute(client, msg).Wait();
            }
            catch (Exception ex)
            {
                unitOfWork.SetException(ex);
                return(false);
            }
            return(true);
        }
示例#14
0
        public static bool SendAPIKey(string email)
        {
            using (var daAPIKeys = new DataAccess.DataAccessObjects.APIKey())
            {
                var key = daAPIKeys.LoadAPIKey(email);

                if (key != null)
                {
                    var msg = new SendGridMessage();

                    msg.SetFrom("*****@*****.**");


                    msg.SetTemplateId("292fe174-26c0-429e-83f6-7443d85eb63e");

                    //string content = File.ReadAllText(HttpContext.Current.Server.MapPath("~/Views/Shared/Other/Email.html"));

                    //content = content.Replace("{email}", email).Replace("{apiKey}", key.APIKey1.ToString());

                    //msg.AddContent(MimeType.Html, content);

                    //msg.Personalizations = new List<Personalization>() {
                    //    new Personalization()
                    //    {
                    //        Tos = new List<EmailAddress>() { new EmailAddress(email) }
                    //    }
                    //};

                    msg.AddTo(key.Email);

                    msg.AddSubstitutions(new Dictionary <string, string>()
                    {
                        { "-email-", email },
                        { "-apiKey-", key.APIKey1.ToString() }
                    });

                    string SG_APIKey = ConfigurationManager.AppSettings["SendGridApiKey"];
                    var    client    = new SendGridClient(SG_APIKey);
                    var    response  = client.SendEmailAsync(msg).Result;
                }

                return(key != null);
            }
        }
示例#15
0
        public bool SendTournamentInviteEmail(TournamentInviteModel invite, string url, List <string> recepiantEmails)
        {
            try
            {
                var msg = new SendGridMessage();

                AccountModel sender = unitOfWork.AccountRepo.Get(invite.Tournament.CreatedByID);
                msg.SetFrom(new EmailAddress(sender.Email, sender.GetFullName()));
                var templateId = "d921bc44-497d-41b4-a670-56f4af8f37a5";
                msg.TemplateId = templateId;


                Dictionary <string, string> substitutions = new Dictionary <string, string>()
                {
                    { "{sender_name}", sender.GetFullName().ToString() },
                    { "{account_creation_url}", "http://localhost:20346/Account/Register" },
                    { "{tournament_title}", invite.Tournament.Title },
                    { "{game_type}", invite.Tournament.GameType.Title },
                    { "{platform}", invite.Tournament.Platform.PlatformName },
                    { "{registration_start_date}", invite.Tournament.RegistrationStartDate.ToShortDateString() },
                    { "{registration_end_date}", invite.Tournament.RegistrationEndDate.ToShortDateString() },
                    { "{tournament_start_date}", invite.Tournament.TournamentStartDate.ToShortDateString() },
                    { "{tournament_url}", url }
                };
                msg.AddSubstitutions(substitutions);

                var recepiants = new List <EmailAddress>();
                foreach (var recepiant in recepiantEmails)
                {
                    recepiants.Add(new EmailAddress(recepiant));
                }
                msg.AddTos(recepiants);


                Execute(client, msg).Wait();
            }
            catch (Exception ex)
            {
                unitOfWork.SetException(ex);
                return(false);
            }
            return(true);
        }
        //Waiting on Template, example of how to use substitution  jutsu
        public async Task Register(EmailBase model)
        {
            Register register = new Register();
            var      msg      = new SendGridMessage()
            {
                From        = new EmailAddress(_config.Email, _config.Sender),
                Subject     = register.Subject,
                HtmlContent = register.HtmlContent
            };
            Dictionary <string, string> subs = new Dictionary <string, string>
            {
                { "-fName-", model.FName },
                { "-lName-", model.LName },
                { "-subject-", "Thank you for Registering" }
            };

            msg.AddSubstitutions(subs);
            msg.AddTo(new EmailAddress(model.To, register.Recipient));
            await Send(msg);
        }
示例#17
0
        public async Task <Response> SendHtmlEmail(EmailAddress recipient, string body, string subject, Dictionary <string, string> substitutions)
        {
            var client = new SendGridClient(ConfigurationHelper.SendGrid_ApiKey);
            var msg    = new SendGridMessage();

            msg.SetFrom(new EmailAddress(Constants.SendGrid_RegisterInternalEmail, Constants.SendGrid_RegisterEmailSubject));

            var recipients = new List <EmailAddress> {
                recipient
            };

            msg.AddTos(recipients);

            msg.SetSubject(subject);
            msg.AddContent(MimeType.Html, body);

            msg.AddSubstitutions(substitutions);

            return(await client.SendEmailAsync(msg));
        }
示例#18
0
        public async Task SendBulkAsync(IEnumerable <Email> emails, string fromEmail = null, CancellationToken cancellation = default)
        {
            // Prepare the SendGridMessage
            var msg = new SendGridMessage();

            msg.SetFrom(new EmailAddress(email: fromEmail ?? _options.DefaultFromEmail, name: _options.DefaultFromName));
            msg.AddContent(MimeType.Html, Placeholder);
            foreach (var(email, index) in emails.Select((e, i) => (e, i)))
            {
                msg.AddTo(new EmailAddress(email.ToEmail), index);
                msg.SetSubject(email.Subject, index);
                msg.AddSubstitutions(new Dictionary <string, string> {
                    { Placeholder, email.Body }
                }, index);
                msg.AddCustomArg(EmailIdKey, email.EmailId.ToString(), index);
                msg.AddCustomArg(TenantIdKey, email.TenantId.ToString(), index);
            }

            // Send it to SendGrid using their official C# library
            await SendEmailAsync(msg, cancellation);
        }
示例#19
0
        public async Task SendEmailAsync(MailMessage message)
        {
            var sendGridMessage = new SendGridMessage
            {
                Subject          = message.Subject,
                From             = new EmailAddress(_globalSettings.Mail.ReplyToEmail, _globalSettings.SiteName),
                HtmlContent      = message.HtmlContent,
                PlainTextContent = message.TextContent,
            };

            sendGridMessage.AddTos(message.ToEmails.Select(e => new EmailAddress(e)).ToList());

            if (message.MetaData?.ContainsKey("SendGridTemplateId") ?? false)
            {
                sendGridMessage.HtmlContent      = " ";
                sendGridMessage.PlainTextContent = " ";
                sendGridMessage.TemplateId       = message.MetaData["SendGridTemplateId"].ToString();
            }

            if (message.MetaData?.ContainsKey("SendGridSubstitutions") ?? false)
            {
                var subs = message.MetaData["SendGridSubstitutions"] as Dictionary <string, string>;
                sendGridMessage.AddSubstitutions(subs);
            }

            if (message.MetaData?.ContainsKey("SendGridCategories") ?? false)
            {
                var cats = message.MetaData["SendGridCategories"] as List <string>;
                sendGridMessage.AddCategories(cats);
            }

            if (message.MetaData?.ContainsKey("SendGridBypassListManagement") ?? false)
            {
                var bypass = message.MetaData["SendGridBypassListManagement"] as bool?;
                sendGridMessage.SetBypassListManagement(bypass.GetValueOrDefault(false));
            }

            await _client.SendEmailAsync(sendGridMessage);
        }
示例#20
0
        public async Task SendEmailAsync(EmailSenderRequest emailSenderRequest)
        {
            if (emailSenderRequest is null)
            {
                throw new ArgumentNullException(nameof(emailSenderRequest));
            }

            var msg = new SendGridMessage();

            if (_testOnly)
            {
                msg.MailSettings                    = new MailSettings();
                msg.MailSettings.SandboxMode        = new SandboxMode();
                msg.MailSettings.SandboxMode.Enable = true;
            }

            msg.SetFrom(new EmailAddress(_emailFromAddress, _emailFromName));

            // First add all of the "To" email addresses. We must first ensure that no
            // email address appears more than once, otherwise SendGrid will throw an error.
            var uniqueToAddresses = emailSenderRequest.To.GroupBy(emailAddress => emailAddress.Email)
                                    .Select(thisToEmail =>
            {
                var firstEmailWithSameAddress = thisToEmail.OrderBy(e => e.Name).First();
                return(new EmailAddress()
                {
                    Email = firstEmailWithSameAddress.Email, Name = firstEmailWithSameAddress.Name
                });
            })
                                    .ToList();

            msg.AddTos(uniqueToAddresses);

            // Now we'll add the "Cc" email addresses. Here we also can't have any duplicates,
            // further to this, we also can't add an address to the "Cc" list if it's already
            // in the list of "To's".
            if (!(emailSenderRequest.Cc is null))
            {
                foreach (var emailAddress in emailSenderRequest.Cc)
                {
                    if (!uniqueToAddresses.Any(uniqueToAddress =>
                                               uniqueToAddress.Email.Equals(
                                                   emailAddress.Email,
                                                   StringComparison.InvariantCultureIgnoreCase))
                        )
                    {
                        msg.AddCc(new EmailAddress(emailAddress.Email, emailAddress.Name));
                    }
                }
            }

            if (!string.IsNullOrEmpty(emailSenderRequest.Message))
            {
                msg.AddContent(emailSenderRequest.MessageIsHtml ? MimeType.Html : MimeType.Text, emailSenderRequest.Message);
            }

            if (!string.IsNullOrEmpty(emailSenderRequest.Subject))
            {
                msg.SetSubject(emailSenderRequest.Subject);
            }

            if (!string.IsNullOrEmpty(emailSenderRequest.TemplateId))
            {
                msg.SetTemplateId(emailSenderRequest.TemplateId);
            }

            if (emailSenderRequest.Substitutions != null)
            {
                msg.AddSubstitutions(emailSenderRequest.Substitutions);
            }

            var sendGridResponse = await _sendGridClient.SendEmailAsync(msg);

            if ((int)sendGridResponse.StatusCode < 200 || (int)sendGridResponse.StatusCode >= 300)
            {
                throw new FailedToSendEmailException();
            }
        }
示例#21
0
        public async Task <TResult> SendEmailMessageAsync <TResult>(
            string templateName,
            string toAddress, string toName,
            string fromAddress, string fromName,
            string subject,
            IDictionary <string, string> substitutionsSingle,
            IDictionary <string, IDictionary <string, string>[]> substitutionsMultiple,
            Func <string, TResult> onSuccess,
            Func <TResult> onServiceUnavailable,
            Func <string, TResult> onFailure)
        {
            var message = new SendGridMessage();

            message.From    = new EmailAddress(fromAddress, fromName);
            message.Subject = subject;
            message.SetClickTracking(false, true);
            //message.TemplateId = templateName;

            var emailMute      = false;
            var toAddressEmail = EastFive.Web.Configuration.Settings.GetString(AppSettings.MuteEmailToAddress,
                                                                               (emailMuteString) =>
            {
                if (emailMuteString.IsNullOrWhiteSpace())
                {
                    return(new EmailAddress(toAddress, toName));
                }
                emailMute = true;
                return(new EmailAddress(emailMuteString, $"MUTED[{toAddress}:{toName}]"));
            },
                                                                               (why) => new EmailAddress(toAddress, toName));

            message.AddTo(toAddressEmail);
            // message.SetClickTracking(false, false);

            var bccAddressesAdded = Web.Configuration.Settings.GetString(AppSettings.BccAllAddresses,
                                                                         copyEmail =>
            {
                var bccAddresses = (copyEmail.IsNullOrWhiteSpace() ? "" : copyEmail)
                                   .Split(',')
                                   .Where(s => !String.IsNullOrWhiteSpace(s))
                                   .Select((bccAddress) => new EmailAddress(bccAddress))
                                   .ToList();
                if (bccAddresses.Any())
                {
                    message.AddBccs(bccAddresses);
                }
                return(true);
            },
                                                                         (why) => false);


            var subsitutionsSingleDictionary = substitutionsSingle
                                               .Select(kvp => new KeyValuePair <string, string>($"--{kvp.Key}--", kvp.Value))
                                               .ToDictionary();

            message.AddSubstitutions(subsitutionsSingleDictionary);
            var client = new global::SendGrid.SendGridClient(apiKey);

            var responseTemplates = await client.RequestAsync(global::SendGrid.SendGridClient.Method.GET, urlPath : $"/templates/{templateName}");

            if (responseTemplates.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                return(onFailure($"The specified template [{templateName}] does not exist."));
            }
            var templateInfo = await responseTemplates.Body.ReadAsStringAsync();

            if (!responseTemplates.StatusCode.IsSuccess())
            {
                return(onFailure($"Failed to aquire template:{templateInfo}"));
            }

            var     converter = new Newtonsoft.Json.Converters.ExpandoObjectConverter();
            dynamic obj       = Newtonsoft.Json.JsonConvert.DeserializeObject <System.Dynamic.ExpandoObject>(templateInfo, converter);
            string  html      = obj.versions[0].html_content;
            var     htmlDoc   = new HtmlAgilityPack.HtmlDocument();

            htmlDoc.LoadHtml(html);
            if (htmlDoc.ParseErrors != null && htmlDoc.ParseErrors.Count() > 0)
            {
                return(onFailure($"Template has parse errors:{htmlDoc.ParseErrors.Select(pe => pe.Reason).Join(";")}"));
            }

            var substitutionsMultipleExpanded = substitutionsMultiple
                                                .NullToEmpty()
                                                .SelectMany(
                (substitutionMultiple) =>
            {
                var matchingNodes = htmlDoc.DocumentNode.SelectNodes($"//*[@data-repeat='--{substitutionMultiple.Key}--']");
                if (!matchingNodes.NullToEmpty().Any())
                {
                    return new HtmlAgilityPack.HtmlNode[] { }
                }
                ;

                var substituations = matchingNodes
                                     .Select(
                    matchingNode =>
                {
                    var parentNode = substitutionMultiple.Value
                                     .Where(
                        subValues =>
                    {
                        if (!matchingNode.Attributes.Contains("data-repeat-selector-key"))
                        {
                            return(true);
                        }
                        if (!matchingNode.Attributes.Contains("data-repeat-selector-value"))
                        {
                            return(true);
                        }
                        var key = matchingNode.Attributes["data-repeat-selector-key"].Value;
                        if (!subValues.ContainsKey(key))
                        {
                            return(false);
                        }
                        var value = matchingNode.Attributes["data-repeat-selector-value"].Value;
                        return(subValues[key] == value);
                    })
                                     .Aggregate(matchingNode.ParentNode,
                                                (parentNodeAggr, subValues) =>
                    {
                        var newChildHtml = subValues
                                           .Aggregate(
                            matchingNode.OuterHtml,
                            (subTextAggr, sub) =>
                        {
                            subTextAggr = subTextAggr.Replace($"--{sub.Key}--", sub.Value);
                            return(subTextAggr);
                        });

                        var childNode = HtmlAgilityPack.HtmlNode.CreateNode(newChildHtml);
                        parentNodeAggr.AppendChild(childNode);
                        return(parentNodeAggr);
                    });

                    parentNode.RemoveChild(matchingNode);
                    //return new KeyValuePair<string, string>(matchingNode.OuterHtml, subText);
                    return(matchingNode);
                })
                                     .ToArray();
                return(substituations);
            })
                                                .ToArray();

            // message.AddSubstitutions(substitutionsMultipleExpanded);
            //message.HtmlContent = htmlDoc.DocumentNode.OuterHtml;
            message.PlainTextContent = htmlDoc.DocumentNode.InnerText;

            message.HtmlContent = subsitutionsSingleDictionary.Aggregate(
                htmlDoc.DocumentNode.OuterHtml,
                (outerHtml, substitutionSingle) =>
            {
                return(outerHtml.Replace($"--{substitutionSingle.Key}--", substitutionSingle.Value));
            });

            // Send the email, which returns an awaitable task.
            try
            {
                var response = await client.SendEmailAsync(message);

                var body = await response.Body.ReadAsStringAsync();

                if (!response.StatusCode.IsSuccess())
                {
                    return(onFailure(body));
                }

                var messageIdHeaders = response.Headers
                                       .Where(header => header.Key == "X-Message-Id");
                if (!messageIdHeaders.Any())
                {
                    return(onSuccess(body));
                }

                var messageIds = messageIdHeaders.First().Value;
                if (!messageIds.Any())
                {
                    return(onSuccess(body));
                }

                var messageId = messageIds.First();
                return(onSuccess(messageId));
            }
            catch (Exception ex)
            {
                //var details = new StringBuilder();

                //details.Append("ResponseStatusCode: " + ex.ResponseStatusCode + ".   ");
                //for (int i = 0; i < ex.Errors.Count(); i++)
                //{
                //    details.Append(" -- Error #" + i.ToString() + " : " + ex.Errors[i]);
                //}

                return(onFailure(ex.ToString()));
            }
        }