Question

Using MvcMailer, the problem is that our emails are being sent without our CSS as inline style attributes.

PreMailer.Net is a C# Library that can read in an HTML source string, and return a resultant HTML string with CSS in-lined.

How do we use them together? Using the scaffolding example in the MvcMailer step-by-step guide, we start out with this example method in our UserMailer Mailer class:

public virtual MvcMailMessage Welcome()
{
    return Populate(x => {
        x.ViewName = "Welcome";
        x.To.Add("some-email@example.com");
        x.Subject = "Welcome";
    });
}
Was it helpful?

Solution

Simply install PreMailer.Net via NugGet

Update the Mailer class:

public virtual MvcMailMessage Welcome()
{
    var message = Populate(x => {
        x.ViewName = "Welcome";
        x.To.Add("some-email@example.com");
        x.Subject = "Welcome";
    });
    message.Body = PreMailer.Net.PreMailer.MoveCssInline(message.Body).Html;
    return message;
}

Done!

OTHER TIPS

If you have a text body with HTML as an alternate view (which I recommend) you'll need to do the following:

  var message = Populate(m =>
  {
       m.Subject = subject;
       m.ViewName = viewName;
       m.To.Add(model.CustomerEmail);

       m.From = new System.Net.Mail.MailAddress(model.FromEmail);
   });

   // get the BODY so we can process it
   var body = EmailBody(message.ViewName);
   var processedBody = PreMailer.Net.PreMailer.MoveCssInline(body, true).Html;

   // start again with alternate view
   message.AlternateViews.Clear();

   // add BODY as alternate view 
   var htmlView = AlternateView.CreateAlternateViewFromString(processedBody, new ContentType("text/html"));
   message.AlternateViews.Add(htmlView);

   // add linked resources to the HTML view
   PopulateLinkedResources(htmlView, message.LinkedResources);

Note: Even if you think you don't care about text it can help with spam filters.

I recommend reading the source for MailerBase to get a better idea what's going on cos all these Populate methods get confusing.

Note: This may not run as-is but you get the idea. I have code (not shown) that parses for any img tags and adds as auto attachments.

Important part is to clear the HTML alternate view. You must have a .text.cshtml file for the text view.

If you're using ActionMailer.Net(.Next), you can do this:

protected override void OnMailSending(MailSendingContext context)
{
    if (context.Mail.IsBodyHtml)
    {
        var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(context.Mail.Body);
        context.Mail.Body = inlineResult.Html;
    }

    for (var i = 0; i < context.Mail.AlternateViews.Count; i++)
    {
        var alternateView = context.Mail.AlternateViews[i];
        if (alternateView.ContentType.MediaType != AngleSharp.Network.MimeTypeNames.Html) continue;

        using (alternateView) // make sure it is disposed
        {
            string content;
            using (var reader = new StreamReader(alternateView.ContentStream))
            {
                content = reader.ReadToEnd();
            }

            var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(content);
            context.Mail.AlternateViews[i] = AlternateView.CreateAlternateViewFromString(inlineResult.Html, alternateView.ContentType);
        }
    }

    base.OnMailSending(context);
}

If you don't like using AngleSharp.Network.MimeTypeNames, you can just use "text/html". AngleSharp comes as a dependency of ActionMailer.Net.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top