Skip to content

Commit f1e494c

Browse files
author
John Campion Jr
authored
feat: added easier setup and use of embedded templates (#16)
* Added simplified configuration for embedded templates
1 parent 7fdd5cd commit f1e494c

10 files changed

Lines changed: 188 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v3.5.0
4+
5+
- Added simplified configuration to setup and use embedded templates with and without the LiquidRenderer.
6+
37
## v3.4.0
48

59
- Added MailPace sender - thanks [@maartenba](https://github.com/maartenba)

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# FluentEmail - All in one email sender for .NET and .NET Core
44

5-
The easiest way to send email from .NET and .NET Core. Use Razor for email templates and send using SendGrid, MailGun, SMTP and more.
5+
The easiest way to send email from .NET and .NET Core. Use Razor or Liquid for email templates and send using SendGrid, MailGun, MailKit, SMTP and more.
66

77
Forked from original by **[@lukencode](https://github.com/lukencode/fluentemail)**
88

@@ -130,6 +130,44 @@ var email = Email
130130
.UsingTemplate(template, new ViewModel { Name = "Luke", Compliment = "Awesome" });
131131
```
132132

133+
## Embedded Templates
134+
135+
There is a set of extensions in `EmbeddedTemplates` that allows for use of embedded templates without specifying the assembly and the path every time.
136+
137+
```csharp
138+
EmbeddedTemplates.Configure(Assembly.GetExecutingAssembly(), "FluentEmail.Core.Tests");
139+
var email = Email
140+
.From(fromEmail)
141+
.To(toEmail)
142+
.Subject(subject)
143+
.UsingTemplateFromEmbedded("templatename.liquid", new ViewModel { Name = "Luke", Compliment = "Awesome" });
144+
```
145+
146+
## Embedded Templates with Liquid Renderer
147+
148+
Because the Liquid templates can also be configured with an embedded provider, there are builder extensions that will configure both the embedded file provider for layouts and the `EmbeddedTemplates` extensions.
149+
150+
There is a default of the executing assembly with Templates in `EmailTemplates`
151+
152+
```csharp
153+
builder.Services.AddFluentEmail("defaultfrom@email.com")
154+
.AddLiquidRendererWithEmbedded(Assembly.GetExecutingAssembly(), "AssemblyName.EmailTemplates")
155+
156+
// These are the same
157+
builder.Services.AddFluentEmail("defaultfrom@email.com")
158+
.AddLiquidRendererWithEmbedded()
159+
```
160+
161+
## How to set all templates as embedded in the `csproj` file
162+
163+
If you want all templates in a folder to automatically be embedded, use the following in your `csproj` file.
164+
165+
```xml
166+
<ItemGroup>
167+
<EmbeddedResource Include="EmailTemplates/**/*.liquid" />
168+
</ItemGroup>
169+
```
170+
133171
## Sending Emails
134172

135173
```csharp

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1212

1313
<PackageLicenseExpression>MIT</PackageLicenseExpression>
14-
<Version>3.4.0</Version>
14+
<Version>3.5.0</Version>
1515

1616

1717
<PublishRepositoryUrl>true</PublishRepositoryUrl>

src/FluentEmail.Core/EmbeddedResourceHelper.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23
using System.Reflection;
34

45
namespace FluentEmail.Core
@@ -7,14 +8,14 @@ internal static class EmbeddedResourceHelper
78
{
89
internal static string GetResourceAsString(Assembly assembly, string path)
910
{
10-
string result;
11-
12-
using (var stream = assembly.GetManifestResourceStream(path))
13-
using (var reader = new StreamReader(stream))
11+
using var stream = assembly.GetManifestResourceStream(path);
12+
if (stream is null)
1413
{
15-
result = reader.ReadToEnd();
14+
throw new Exception($"{path} was not found in embedded resources.");
1615
}
1716

17+
using var reader = new StreamReader(stream);
18+
var result = reader.ReadToEnd();
1819
return result;
1920
}
2021
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Reflection;
3+
4+
namespace FluentEmail.Core;
5+
6+
public static class EmbeddedTemplates
7+
{
8+
private static Assembly _assembly;
9+
private static string _rootPath;
10+
11+
public static void Configure(Assembly assembly, string rootPath)
12+
{
13+
_assembly = assembly;
14+
_rootPath = rootPath;
15+
}
16+
17+
/// <summary>
18+
/// Adds template to email from previously configured default embedded resource
19+
/// </summary>
20+
/// <typeparam name="T"></typeparam>
21+
/// <param name="path">Path the the embedded resource eg [YourResourceFolder].[YourFilename.txt]. Will be appended to configured root path</param>
22+
/// <param name="model">Model for the template</param>
23+
/// <param name="isHtml">True if Body is HTML (default), false for plain text</param>
24+
/// <returns></returns>
25+
public static IFluentEmail UsingTemplateFromEmbedded<T>(this IFluentEmail email, string path, T model, bool isHtml = true)
26+
{
27+
if (_assembly is null)
28+
{
29+
throw new Exception("FluentEmailEmbeddedExtensions.Configure must be called with default assembly and root path");
30+
}
31+
32+
var root = _rootPath;
33+
if (!string.IsNullOrEmpty(root)) root += ".";
34+
var template = EmbeddedResourceHelper.GetResourceAsString(_assembly, $"{root}{path}");
35+
var result = email.Renderer.Parse(template, model, isHtml);
36+
email.Data.IsHtml = isHtml;
37+
email.Data.Body = result;
38+
39+
return email;
40+
}
41+
42+
/// <summary>
43+
/// Adds alternative plaintext template to email from previously configured embedded resource
44+
/// </summary>
45+
/// <typeparam name="T"></typeparam>
46+
/// <param name="path">Path the the embedded resource eg [YourResourceFolder].[YourFilename.txt]. Will be appended to configured root path</param>
47+
/// <param name="model">Model for the template</param>
48+
/// <returns></returns>
49+
public static IFluentEmail PlaintextAlternativeUsingTemplateFromEmbedded<T>(this IFluentEmail email, string path, T model)
50+
{
51+
var root = _rootPath;
52+
if (!string.IsNullOrEmpty(root)) root += ".";
53+
var template = EmbeddedResourceHelper.GetResourceAsString(_assembly, $"{root}{path}");
54+
var result = email.Renderer.Parse(template, model, false);
55+
email.Data.PlaintextAlternativeBody = result;
56+
57+
return email;
58+
}
59+
60+
}

src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
<ItemGroup>
1717
<PackageReference Include="Fluid.Core" Version="2.3.1" />
18+
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.13" />
1819
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
1920
</ItemGroup>
2021

src/Renderers/FluentEmail.Liquid/FluentEmailFluidBuilderExtensions.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
2-
2+
using System.Reflection;
3+
using FluentEmail.Core;
34
using FluentEmail.Core.Interfaces;
45
using FluentEmail.Liquid;
56

67
using Microsoft.Extensions.DependencyInjection.Extensions;
8+
using Microsoft.Extensions.FileProviders;
79

810
// ReSharper disable once CheckNamespace
911
namespace Microsoft.Extensions.DependencyInjection
@@ -23,5 +25,50 @@ public static FluentEmailServicesBuilder AddLiquidRenderer(
2325
builder.Services.TryAddSingleton<ITemplateRenderer, LiquidRenderer>();
2426
return builder;
2527
}
28+
29+
public static FluentEmailServicesBuilder AddLiquidRendererWithEmbedded(
30+
this FluentEmailServicesBuilder builder,
31+
Action<LiquidRendererOptions>? configure = null)
32+
{
33+
var assembly = Assembly.GetExecutingAssembly();
34+
var name = assembly.GetName().Name;
35+
return AddLiquidRendererWithEmbedded(builder, assembly, $"{name}.EmailTemplates", configure);
36+
}
37+
38+
public static FluentEmailServicesBuilder AddLiquidRendererWithEmbedded(
39+
this FluentEmailServicesBuilder builder,
40+
Assembly assembly,
41+
Action<LiquidRendererOptions>? configure = null)
42+
{
43+
var name = assembly.GetName().Name;
44+
return AddLiquidRendererWithEmbedded(builder, assembly, $"{name}.EmailTemplates", configure);
45+
}
46+
47+
public static FluentEmailServicesBuilder AddLiquidRendererWithEmbedded(
48+
this FluentEmailServicesBuilder builder,
49+
string rootPath,
50+
Action<LiquidRendererOptions>? configure = null)
51+
{
52+
var assembly = Assembly.GetExecutingAssembly();
53+
var name = assembly.GetName().Name;
54+
if (!string.IsNullOrEmpty(rootPath)) name += ".";
55+
return AddLiquidRendererWithEmbedded(builder, assembly, $"{name}{rootPath}", configure);
56+
}
57+
58+
public static FluentEmailServicesBuilder AddLiquidRendererWithEmbedded(
59+
this FluentEmailServicesBuilder builder,
60+
Assembly assembly,
61+
string rootNamespace,
62+
Action<LiquidRendererOptions>? configure = null)
63+
{
64+
builder.AddLiquidRenderer(options =>
65+
{
66+
options.FileProvider = new EmbeddedFileProvider(assembly, rootNamespace);
67+
configure?.Invoke(options);
68+
});
69+
EmbeddedTemplates.Configure(assembly, rootNamespace);
70+
return builder;
71+
}
72+
2673
}
2774
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
yo email ##Test##

test/FluentEmail.Core.Tests/FluentEmail.Core.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<None Update="*.txt">
2929
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3030
</None>
31+
<EmbeddedResource Include="EmailTemplates\test-embedded.txt" />
3132
<EmbeddedResource Include="test-embedded.txt" />
3233
<PackageReference Include="FluentAssertions" Version="6.9.0" />
3334
<None Update="logotest.png">

test/FluentEmail.Core.Tests/TemplateEmailTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,32 @@ public void Using_Template_From_Embedded_Resource()
109109

110110
Assert.AreEqual("yo email EMBEDDEDTEST", email.Data.Body);
111111
}
112+
113+
[Test]
114+
public void Using_Template_From_Root_Configured_Embedded_Resource()
115+
{
116+
EmbeddedTemplates.Configure(Assembly.GetExecutingAssembly(), "FluentEmail.Core.Tests");
117+
var email = Email
118+
.From(fromEmail)
119+
.To(toEmail)
120+
.Subject(subject)
121+
.UsingTemplateFromEmbedded("test-embedded.txt", new { Test = "EMBEDDEDTEST" });
122+
123+
Assert.AreEqual("yo email EMBEDDEDTEST", email.Data.Body);
124+
}
125+
126+
[Test]
127+
public void Using_Template_From_Configured_Embedded_Resource()
128+
{
129+
EmbeddedTemplates.Configure(Assembly.GetExecutingAssembly(), "FluentEmail.Core.Tests.EmailTemplates");
130+
var email = Email
131+
.From(fromEmail)
132+
.To(toEmail)
133+
.Subject(subject)
134+
.UsingTemplateFromEmbedded("test-embedded.txt", new { Test = "EMBEDDEDTEST" });
135+
136+
Assert.AreEqual("yo email EMBEDDEDTEST", email.Data.Body);
137+
}
112138

113139
[Test]
114140
public void New_Anonymous_Model_Template_From_File_Matches()

0 commit comments

Comments
 (0)