Macro

v 18.0.0

Email Control: Macro

The Macro-control makes it possible to include dynamic content, generated with a cshtml file, in both Campaign and Transactional Emails.

This can be used to generate recipient-specific content like discounts, promotions, personalized content or render a receipt. When using a Macro you have 100% control over the rendered HTML.

Creating a Macro

Macros can be created in two ways, either as Global or as Theme-specific.

Global

When you want a Macro to be usable everywhere in the email editor, just add a cshtml file like this:

App_Plugins/newsletterStudioExtensions/views/macros/myNewMacro.cshtml

Theme-specific

A theme-specific Macro only works when this theme is used. To create a Theme-specific macro, add a file like this:

App_Plugins/mySite/newsletterStudio/themes/myTheme/views/macros/myNewMacro.cshtml

Example of Macro-content

@model NewsletterStudio.Core.Editor.Controls.Macro.EmailMacroViewModel

<p>Demo cshtml-Macro Rendering</p>

<strong>Email</strong><br/>
@Model.RecipientDataModel.Email

<strong>Merge Fields</strong><br/>
<ul>
    @foreach (var field in Model.RecipientDataModel.MergeFields)
    {
        <li>
            @field.Placeholder: @field.Value
        </li>
    }
</ul>

<strong>Transactional Model</strong><br/>
Has Model: @(Model.TransactionalModel == null ? "No" : "Yes")

@if (Model.TransactionalModel != null)
{
    <text>Model Type: @Model.TransactionalModel.GetType() </text>
}

@* Example of how to look for a given Transactional Model if the macro needs to read data from the model *@

@if (Model.TransactionalModel is ForgotPasswordModel data)
{
    <p>Data from model: @data.Data.Name</p>
}

Injecting dependencies

Views inside a macro support injecting dependencies using @inject, just like any other Razor view. Here is an example of how to access the UmbracoContext from within a macro:

@using Umbraco.Cms.Core.Web
@inject IUmbracoContextFactory UmbracoContextFactory
@{
    var pageName = "";
    using (var ctx = UmbracoContextFactory.EnsureUmbracoContext())
    {
        pageName = ctx.UmbracoContext.Content.GetById(1057).Name;
    }
}

<h2>@pageName</h2>

Be aware: Do not use accessors like IUmbracoContextAccessor or IHttpContextAccessor inside macro views as they are rendered in a background thread during send out. If you need access to published content, use IUmbracoContextFactory as in the example above which is not request bound. Make sure to send your campaigns/transactional emails to a test SMTP-server or SMTP Pickup Directory to make sure that rendering works as expected. Do not rely on previews as they are rendered by an HTTP request, hence might have access to dependencies that are not accessible in a background thread.

Publish a site with Macros

When you run your Umbraco site in Production Mode, views used by the application must be compiled. Views inside the App_Plugins-folder are not compiled by default. Add this to your .csproj to ensure that the .cshtml files are compiled:

<ItemGroup>    
  <RazorGenerate Include="App_Plugins\**\*.cshtml" />
</ItemGroup>