public static string Inline(string source) { using var pm = new PreMailer.Net.PreMailer(source); var html = pm.MoveCssInline(css: EmailCssContent, removeComments: true, stripIdAndClassAttributes: false, removeStyleElements: false).Html; return(html); }
/// <summary> /// In-lines the CSS for the current HTML /// </summary> /// <param name="removeStyleElements">If set to <c>true</c> the style elements are removed.</param> /// <param name="ignoreElements">CSS selector for STYLE elements to ignore (e.g. mobile-specific styles etc.)</param> /// <param name="css">A string containing a style-sheet for inlining.</param> /// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param> /// <param name="removeComments">True to remove comments, false to leave them intact</param> /// <param name="precompiledStyles"></param> /// <returns>Returns the html input, with styles moved to inline attributes.</returns> public InlineResult MoveCssInline(bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, SortedList <string, StyleClass> precompiledStyles = null) { // Store the variables used for inlining the CSS _removeStyleElements = removeStyleElements; _stripIdAndClassAttributes = stripIdAndClassAttributes; _ignoreElements = ignoreElements; // Gather all of the CSS that we can work with. var cssSourceNodes = CssSourceNodes(); var cssLinkNodes = CssLinkNodes(); var cssSources = new List <ICssSource>(ConvertToStyleSources(cssSourceNodes)); cssSources.AddRange(ConvertToStyleSources(cssLinkNodes)); cssSources.AddRange(PreMailer.ConvertToStyleSources(css)); var cssBlocks = PreMailer.GetCssBlocks(cssSources); if (_removeStyleElements) { RemoveStyleElements(cssSourceNodes); RemoveStyleElements(cssLinkNodes); } var joinedBlocks = PreMailer.Join(cssBlocks); var validSelectors = CleanUnsupportedSelectors(joinedBlocks); if (precompiledStyles != null) { precompiledStyles.ToList().ForEach(kvp => { validSelectors.Add(kvp.Key, kvp.Value); }); } var elementsWithStyles = FindElementsWithStyles(validSelectors); var mergedStyles = MergeStyleClasses(elementsWithStyles); StyleClassApplier.ApplyAllStyles(mergedStyles); if (_stripIdAndClassAttributes) { StripElementAttributes("id", "class"); } if (removeComments) { var comments = _document.Descendents <IComment>().ToList(); foreach (var comment in comments) { comment.Remove(); } } var html = _document.ToHtml(new AutoSelectedMarkupFormatter(_document.Doctype)); return(new InlineResult(html, _warnings)); }
/// <summary> /// Function to precompile a style sheet allowing it be be preserved in /// memory for performance purposes. /// </summary> /// <param name="css">A string containing a style-sheet for inlining.</param> /// <param name="warnings">A list of warnings indicating css elements that are not supported.</param> /// <returns>A tokenized sorted list representing the css that was passed in</returns> public static SortedList <string, StyleClass> PrecompileCssString(string css, out List <string> warnings) { var cssSource = new List <ICssSource>(PreMailer.ConvertToStyleSources(css)); var cssBlocks = PreMailer.GetCssBlocks(cssSource); var joinedBlocks = PreMailer.Join(cssBlocks); warnings = new List <string>(); var cleanJoinedBlocks = PreMailer.CleanUnsupportedSelectors(joinedBlocks, warnings); return(cleanJoinedBlocks); }
public string GenerateEmailBody(PersonModel model) { // Create a model for our email var templateFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "EmailTemplates"); var templateFilePath = Path.Combine(templateFolderPath, "Email.cshtml"); // Generate the email body from the template file. // 'templateFilePath' should contain the absolute path of your template file. //var TemplateService = new TemplateService(); var emailHtmlBody = TemplateService.Parse(File.ReadAllText(templateFilePath), model, null, "Email"); /* * Move CSS Inline. https://github.com/milkshakesoftware/PreMailer.Net */ var pm = new PreMailer.Net.PreMailer(emailHtmlBody); //pm.AddAnalyticsTags(source, medium, campaign, content, domain = null); // Optional to add analytics tags var result = pm.MoveCssInline(); return(result.Html); }
/// <summary> /// /// </summary> /// <param name="mailInfo"></param> /// <param name="recepients">receivers</param> /// <param name="testMode">No mails are sent, generating report for user</param> /// <returns>A html formatted report of the send process</returns> public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode) { _log.Debug("Starting Send"); // for logging SendMailLog log = new SendMailLog(); // Need someone to send to if (recepients.Items.Count == 0) { _log.Error("Trying to send newsletter with an empty JobWorkCollection. Please check the collection before attemting to send mail."); throw new ArgumentNullException("recepients", "Recipient collection is empty, there is no recipients to send to."); } // And, we need a sender address if (string.IsNullOrEmpty(mailInfo.From)) { _log.Error("Missing from address."); throw new ArgumentNullException("mailInfo", "Missing from address."); } // Inline all css PreMailer.Net.PreMailer preMailer = new PreMailer.Net.PreMailer(mailInfo.BodyHtml); if (mailInfo.Utm.HasValidUtmCode) { preMailer.AddAnalyticsTags(mailInfo.Utm.Source, mailInfo.Utm.Medium, mailInfo.Utm.Campaign, mailInfo.Utm.Content); } InlineResult cssInline = preMailer.MoveCssInline(); mailInfo.BodyHtml = cssInline.Html; // Log any messages, debug is only detected // if we have an HttpContext. if (IsInDebugMode()) { log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers."); log.WarningMessages.AddRange(cssInline.Warnings.ToArray()); } // Loop through receivers collection, add to collection and send // one email per batch size. int batchRun = 0; int batchSize = GetBatchSize(); do { IEnumerable<JobWorkItem> workItems = recepients.Skip(batchRun*batchSize).Take(batchSize); int numberofItemsToSend = workItems.Count(); if (numberofItemsToSend == 0) break; batchRun++; try { if (SendMailBatch(mailInfo, workItems, testMode)) { // Mark each item as sent foreach (JobWorkItem workItem in workItems) { log.SuccessMessages.Add(workItem.EmailAddress); // Update status and save it workItem.Status = JobWorkStatus.Complete; // Only save if real work item (could be a test item) if (workItem.JobId > 0) workItem.Save(); } } } catch (Exception ex) { _log.Error(string.Format("Error sending batch (to {0} recipients).", recepients.Count()), ex); string exceptionMsg = ex.Message; log.ErrorMessages.Add(exceptionMsg); // Update work item foreach (JobWorkItem workItem in workItems) { workItem.Status = JobWorkStatus.Failed; if (exceptionMsg.Length >= 2000) exceptionMsg = exceptionMsg.Substring(0, 1999); workItem.Info = exceptionMsg; if (workItem.JobId > 0) workItem.Save(); } // can't continue break; } } while (true); // Finished log.SendStop = DateTime.Now; _log.Debug("Ending Send"); // return report return log; }
/// <summary> /// In-lines the CSS within the HTML given. /// </summary> /// <param name="html">The HTML input.</param> /// <param name="removeStyleElements">If set to <c>true</c> the style elements are removed.</param> /// <param name="ignoreElements">CSS selector for STYLE elements to ignore (e.g. mobile-specific styles etc.)</param> /// <returns>Returns the html input, with styles moved to inline attributes.</returns> public static InlineResult MoveCssInline(string html, bool removeStyleElements = false, string ignoreElements = null) { var pm = new PreMailer(html, removeStyleElements, ignoreElements); return pm.Process(); }
/// <summary> /// In-lines the CSS within the HTML given. /// </summary> /// <param name="html">The HTML input.</param> /// <param name="removeStyleElements">If set to <c>true</c> the style elements are removed.</param> /// <param name="ignoreElements">CSS selector for STYLE elements to ignore (e.g. mobile-specific styles etc.)</param> /// <param name="css">A string containing a style-sheet for inlining.</param> /// <returns>Returns the html input, with styles moved to inline attributes.</returns> public static InlineResult MoveCssInline(string html, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false) { var pm = new PreMailer(html, removeStyleElements, ignoreElements, css, stripIdAndClassAttributes); return(pm.Process()); }
/// <summary> /// In-lines the CSS within the HTML given. /// </summary> /// <param name="html">The HTML input.</param> /// <param name="removeStyleElements">If set to <c>true</c> the style elements are removed.</param> /// <param name="ignoreElements">CSS selector for STYLE elements to ignore (e.g. mobile-specific styles etc.)</param> /// <returns>Returns the html input, with styles moved to inline attributes.</returns> public static InlineResult MoveCssInline(string html, bool removeStyleElements = false, string ignoreElements = null) { var pm = new PreMailer(html, removeStyleElements, ignoreElements); return(pm.Process()); }
/// <summary> /// /// </summary> /// <param name="mailInfo"></param> /// <param name="recepients">receivers</param> /// <param name="testMode">No mails are sent, generating report for user</param> /// <returns>A html formatted report of the send process</returns> public override SendMailLog SendEmail(MailInformation mailInfo, JobWorkItems recepients, bool testMode) { _log.Debug("Starting Send"); // for logging SendMailLog log = new SendMailLog(); // Need someone to send to if (recepients.Items.Count == 0) { _log.Error("Trying to send newsletter with an empty JobWorkCollection. Please check the collection before attemting to send mail."); throw new ArgumentNullException("recepients", "Recipient collection is empty, there is no recipients to send to."); } // And, we need a sender address if (string.IsNullOrEmpty(mailInfo.From)) { _log.Error("Missing from address."); throw new ArgumentNullException("mailInfo", "Missing from address."); } // Inline all css PreMailer.Net.PreMailer preMailer = new PreMailer.Net.PreMailer(mailInfo.BodyHtml); if (mailInfo.Utm.HasValidUtmCode) { preMailer.AddAnalyticsTags(mailInfo.Utm.Source, mailInfo.Utm.Medium, mailInfo.Utm.Campaign, mailInfo.Utm.Content); } InlineResult cssInline = preMailer.MoveCssInline(); mailInfo.BodyHtml = cssInline.Html; // Log any messages, debug is only detected // if we have an HttpContext. if (IsInDebugMode()) { log.WarningMessages.Add("Premailer CSS warning messages are only shown in debug mode. Primarily for developers."); log.WarningMessages.AddRange(cssInline.Warnings.ToArray()); } // Loop through receivers collection, add to collection and send // one email per batch size. int batchRun = 0; int batchSize = GetBatchSize(); do { IEnumerable <JobWorkItem> workItems = recepients.Skip(batchRun * batchSize).Take(batchSize); int numberofItemsToSend = workItems.Count(); if (numberofItemsToSend == 0) { break; } batchRun++; try { if (SendMailBatch(mailInfo, workItems, testMode)) { // Mark each item as sent foreach (JobWorkItem workItem in workItems) { log.SuccessMessages.Add(workItem.EmailAddress); // Update status and save it workItem.Status = JobWorkStatus.Complete; // Only save if real work item (could be a test item) if (workItem.JobId > 0) { workItem.Save(); } } } } catch (Exception ex) { _log.Error(string.Format("Error sending batch (to {0} recipients).", recepients.Count()), ex); string exceptionMsg = ex.Message; log.ErrorMessages.Add(exceptionMsg); // Update work item foreach (JobWorkItem workItem in workItems) { workItem.Status = JobWorkStatus.Failed; if (exceptionMsg.Length >= 2000) { exceptionMsg = exceptionMsg.Substring(0, 1999); } workItem.Info = exceptionMsg; if (workItem.JobId > 0) { workItem.Save(); } } // can't continue break; } } while (true); // Finished log.SendStop = DateTime.Now; _log.Debug("Ending Send"); // return report return(log); }