0

Let me start by saying there may be a better way to go about this so by all means feel free to suggest a different approach.

What I am trying to do is send an email from a template in a Blazor server side application. The email library (MailKit) needs the body to be rendered as a string as I understand it.

Of course I want this to be a template so my thought process was to have a cshtml page with a model. Render it with the model passed in and take the output string and use that for the body.

So my mailing code would look like this:

var email = new MimeKit.MimeMessage();
        email.From.Add(MimeKit.MailboxAddress.Parse(_mailOptions.Value.DefaultFrom));
        email.To.Add(MimeKit.MailboxAddress.Parse(toemail));
        email.Subject = subject;
        email.Body = new MimeKit.TextPart(MimeKit.Text.TextFormat.Html) { Text = cshtmlRenderedText };

        _smtpClient.Send(email);
        _smtpClient.Disconnect(true);

So I need to be able to process the cshtml and the model without activating a controller so I have this routine I found from here.

I think everything will process fine except it can't find my cshtml files. Why is that?

var viewResult = _razorViewEngine.FindView(actionContext, "ConfirmUser.cshtml", false);

I've tried hard coding all sorts of path variations but nothing seems to actually find my view as viewResult.View is always null.

Perhaps it IS finding my cshtml but it's not "valid" for some reason so here is the file:

@model Project.API.Infrastructure.Email.ConfirmUser.ConfirmUserEmailViewModel;

@{
   <p>Welcome @Model.Name,</p>

   <p>Please confirm your email by <a href='@Model.ConfirmUrl'>clicking here</a>.</p>

   <p>If you prefer you can copy and paste this link into your browser of choice.</p>
   <br />
   <p>@Model.ConfirmUrl</p>
   <br />

}

There is a similar question here with a work-around not really an answer.

How can I path to my cshtml file or is there a better way of rendering to string for an email body?

halfer
  • 19,824
  • 17
  • 99
  • 186
GPGVM
  • 5,515
  • 10
  • 56
  • 97

1 Answers1

1

You're in luck - I had the same problem a few months ago when trying to use RazorLight (a similar .cshtml templater) and ran into too many problems.

I realised that .razor files are so much better suited to this use case than .cshtml files since they compile to plain C# classes - except nothing was available to render them. So I wrote BlazorTemplater which does exactly that.

  1. Install the Blazor Templater Nuget Package
  2. Convert your .cshtml file to .razor (e.g. ConfirmUser.razor) and switch from importing a Model to using .razor parameters, e.g.
 <p>Welcome @Model.Name,</p>

   <p>Please confirm your email by <a href='@Model.ConfirmUrl'>clicking here</a>.</p>

   <p>If you prefer you can copy and paste this link into your browser of choice.</p>
   <br />
   <p>@Model.ConfirmUrl</p>
   <br />
@code {
  [Parameter] public ConfirmUserEmailViewModel Model {get;set;}
}
  1. Render the component to HTML:
var viewResult = new ComponentRendered<ConfirmUser>()
      .Set(v => v.Model, myModel)
      .Render();
Quango
  • 12,338
  • 6
  • 48
  • 83
  • @Quango...I'll give that a try. I came up with another approach using a StreamReader to find the file and then RazorLight to parse it. Kinda heavy handed but it worked. – GPGVM Sep 11 '21 at 15:08
  • As per your issue on my repo, I've edited the reply as I used the wrong syntax! Apologies. I think you'll find BlazorTemplater useful - it's very easy to get started and very flexible. – Quango Sep 11 '21 at 18:37