Rendering Emails with Liquid (Fluid)
Relevant source files
The following files were used as context for generating this wiki page:
The Resend .NET SDK supports HTML email generation using the Fluid rendering engine. Fluid implements the Liquid template language, providing a secure and accessible way to manage complex HTML structures without embedding raw HTML strings directly in C# code. This approach separates presentation logic from application code, improving maintainability and reducing syntax errors in email bodies.
Sources: examples/README.md:95-103, examples/RenderLiquid/README.md:1-5
System Architecture
The rendering system operates by loading Liquid templates stored as embedded resources, parsing them into thread-safe templates, and executing them against a model-specific context. The generated HTML string is then assigned to the HtmlBody property of an EmailMessage object for transmission via the Resend API.
Rendering Component Flow
The following diagram illustrates the lifecycle of a Liquid template from resource loading to final HTML output.
The rendering logic resides primarily in the RenderEmail<T> method within the controller. It retrieves the .liquid file using the namespace and assembly of the provided model type.
Sources: examples/RenderLiquid/Controllers/EmailController.cs:72-117, examples/README.md:100-103
Implementation Details
The implementation utilizes FluidParser for template compilation and TemplateContext for binding data models to those templates.
Key Components
| Component | Description | Thread Safety |
|---|---|---|
FluidParser | Converts raw Liquid text into an executable template. | Thread-safe; share across application. |
IFluidTemplate | The compiled representation of the Liquid source. | Thread-safe; should be cached. |
TemplateContext | Holds the model data and options for a specific render. | Not thread-safe. |
EmailMessage | The Resend SDK object that stores the final HTML body. | N/A |
Sources: examples/RenderLiquid/Controllers/EmailController.cs:97-105, examples/RenderLiquid/Controllers/EmailController.cs:56-62
Template Retrieval Logic
Templates are resolved by naming convention. The system identifies the .liquid file by combining the namespace of the model class with the requested view name.
var type = typeof( T );
var resx = $"{type.Namespace}.{view}.liquid";
using ( var stream = type.Assembly.GetManifestResourceStream( resx ) )
{
// ... Read stream to source string
}
Sources: examples/RenderLiquid/Controllers/EmailController.cs:76-85
Data Flow for Email Sending
When sending a rendered email, the application follows a synchronous sequence of rendering followed by an asynchronous API call to Resend.
Configuration and Setup
To use Liquid rendering, you must configure the Resend client in the application startup. The RESEND_APITOKEN environment variable must be set for the client to authenticate with the Resend service.
- Register Resend services via
builder.Services.AddHttpClient<ResendClient>(). - Configure options using
builder.Services.Configure<ResendClientOptions>. - Inject
IResendinto the controller to handle the final transmission.
Sources: examples/RenderLiquid/Program.cs:22-31, examples/RenderLiquid/README.md:12-14, README.md:46-52
Best Practices
- Caching: Cache
IFluidTemplateinstances to avoid repeated parsing of the same.liquidfiles. - Parser Management: Use a singleton instance of
FluidParserfor the entire application duration. - Resource Management: Ensure
.liquidfiles are marked as "Embedded Resource" in the project file so they are available viaGetManifestResourceStream. - Error Handling: Validate that
parser.TryParsesucceeds before attempting to render, as Liquid syntax errors will prevent template generation.
Sources: examples/RenderLiquid/Controllers/EmailController.cs:97-111, examples/RenderLiquid/Controllers/EmailController.cs:81-83
Summary
Rendering with Liquid via the Fluid engine allows developers to create dynamic, data-driven email content for the Resend .NET SDK. By utilizing embedded resources and a strongly-typed model context, the system provides a robust framework for generating HTML bodies that are clean, maintainable, and decoupled from the application's core logic.