23

Postalを使用して MVC Razor ビューをレンダリングし、電子メールで送信しています。メール ビュー専用に定義したカスタム CSS があります。現在、私は次のようにそれらを含めています:

@Styles.Render("~/Content/EmailStyles.css")

ただし、これにはスタイルシートへの相対リンクのみが含まれており、電子メールでは機能しません。

<link href="/Content/EmailStyles.css" rel="stylesheet"/>

メールで適切に機能するように、スタイルシートをインラインで含めたいと考えています。MVC ビュー内でファイルベースのリソースのコンテンツをレンダリングする最良の方法は何ですか?

4

4 に答える 4

37

私も同じ質問をして、Premailer.Netに出会いました。必要なライブラリのようです。これがあなたがしなければならないことです:

  1. CSS をページに埋め込むのに役立つ拡張メソッドを作成します。HTML を Razor ビューに埋め込む方法に関する質問には、役立つはずの回答があります。CSSを埋め込むために修正しました:

    public static class HtmlHelpers
    {
        public static MvcHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
        {
            // take a path that starts with "~" and map it to the filesystem.
            var cssFilePath = HttpContext.Current.Server.MapPath(path);
            // load the contents of that file
            try
            {
                var cssText = System.IO.File.ReadAllText(cssFilePath);
                var styleElement = new TagBuilder("style");
                styleElement.InnerHtml = cssText;
                return MvcHtmlString.Create(styleElement.ToString());
            }
            catch (Exception ex)
            {
                // return nothing if we can't read the file for any reason
                return null;
            }
        }
    }
    
  2. 次に、Razor テンプレートで次のようにします。

    @Html.EmbedCss("~/Content/EmailStyles.css")
    

    CSS テキストを埋め込みます。

  3. プロジェクトに Premailer.Net パッケージをインストールします。NuGet から取得できます。

  4. Razor ビューを文字列にレンダリングします (それが Postal のプロセスの目的だと思いますか? RazorEngineもそれを行うことができると思います)。

  5. Premailer.Net を介して文字列を実行します。

    PreMailer pm = new PreMailer();
    string premailedOutput = pm.MoveCssInline(htmlSource, false);
    
  6. メールで送信!

私はしばらくの間、この手法を本番環境で使用してきましたが、非常にうまく機能しているようです。

編集:疑似要素のスタイルはマークアップに存在しないため、インライン化できないことに注意してください。また、Premailer.Net の奇妙な小さなバグにも気付きました。それらの特異性とカスケード ルールは、完全には準拠していないと思います。それでも、それはかなり良いものであり、私が書く必要のないコードが 1 つ増えました!

于 2013-03-15T23:23:26.310 に答える
13

Paul d'Aoustの回答に賛成しましたが、彼のヘルパーメソッドのこのバージョンが少しうまく機能することがわかりました(CSSで引用符のようなものをエンコードしようとしません):

public static class CssHelper
{
  public static IHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
  {
    // take a path that starts with "~" and map it to the filesystem.
    var cssFilePath = HttpContext.Current.Server.MapPath(path);
    // load the contents of that file
    try
    {
      var cssText = File.ReadAllText(cssFilePath);
      return htmlHelper.Raw("<style>\n" + cssText + "\n</style>");
    }
    catch
    {
      // return nothing if we can't read the file for any reason
      return null;
    }
  }
}
于 2015-09-11T20:08:09.670 に答える
1

そのためのカスタムヘルパーが必要になると思います。私の頭の上には、Web サイトの絶対パスを含む css パスをレンダリングする方法はありません。

例 http:www.example.com/css/EmailStyles.css

于 2013-01-12T22:33:50.037 に答える
0

これは古い質問だと思いますが、バンドルを埋め込むdprotheroの回答の修正版を次に示します。静的 C# クラスを作成し、このメソッドをその中に入れます。

public static IHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
{
  try
  {
      // Get files from bundle
      StyleBundle b = (StyleBundle)BundleTable.Bundles.GetBundleFor("~/Content/css");
      BundleContext bc = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, "~/Content/css");
      List<BundleFile> files = b.EnumerateFiles(bc).ToList();
      // Create string to return
      string stylestring = "";
      // Iterate files in bundle
      foreach(BundleFile file in files)
      {
          // Get full path to file
          string filepath = HttpContext.Current.Server.MapPath(file.IncludedVirtualPath);
          // Read file text and append to style string
          string filetext = File.ReadAllText(filepath);
          stylestring += $"<!-- Style for {file.IncludedVirtualPath} -->\n<style>\n{filetext}\n</style>\n";
      }
      return htmlHelper.Raw(stylestring);
  }
  catch
  {
      // return nothing if we can't read the file for any reason
      return null;
  }

次に、それを使用したいビューに移動します。ビューに CSS ヘルパーが表示されるように、必ず using ステートメントを追加してください。また、TempData を使用して、インラインでレンダリングするかどうかを決定します。

<!-- Using statement -->
@using Namespace.Helpers;

<!-- Check tempdata flag for whether or not to render inline -->
@if (TempData["inlinecss"] != null)
{
    <!-- Embed CSS with custom code -->
    @Html.EmbedCss("~/Content/css")
}
else
{
    <!-- Use links to reference CSS -->
    @Styles.Render("~/Content/css")
}
于 2021-06-28T15:49:19.867 に答える