Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

Where templates live

All email templates are in src/Acme.Infrastructure/Email/Templates/. Each template is a C# class that extends EmailTemplateBase.
src/Acme.Infrastructure/Email/Templates/
├── EmailTemplateBase.cs          ← base class with HTML scaffolding
├── WelcomeTemplate.cs
├── EmailVerificationTemplate.cs
├── PasswordResetTemplate.cs
├── MagicLinkTemplate.cs
├── PasswordChangedTemplate.cs
├── TenantInvitationTemplate.cs
├── TrialExpiry7DayTemplate.cs
├── TrialExpiry1DayTemplate.cs
├── PaymentFailedTemplate.cs
├── PaymentRecoveredTemplate.cs
├── CancellationScheduledTemplate.cs
└── CancellationConfirmedTemplate.cs

How templates work

EmailTemplateBase provides:
  • The outer HTML envelope (DOCTYPE, <head>, brand color, inline styles)
  • Header with the application name
  • Footer with unsubscribe language
  • Abstract RenderContent() method that each template implements
Each template class fills in RenderContent() with its specific body HTML:
// EmailVerificationTemplate.cs
public class EmailVerificationTemplate : EmailTemplateBase
{
    private readonly string _userName;
    private readonly string _verificationUrl;

    public EmailVerificationTemplate(string userName, string verificationUrl)
    {
        _userName = userName;
        _verificationUrl = verificationUrl;
    }

    protected override string RenderContent()
    {
        return $"""
            <h2 style="color: #1A56DB; font-size: 20px; margin: 0 0 16px;">
                Verify your email address
            </h2>
            <p style="color: #374151; margin: 0 0 24px;">
                Hi {_userName}, click the button below to verify your email address.
                This link expires in 24 hours.
            </p>
            <a href="{_verificationUrl}"
               style="background: #1A56DB; color: white; padding: 12px 24px;
                      text-decoration: none; border-radius: 6px; display: inline-block;">
                Verify Email
            </a>
            """;
    }
}

Changing the brand color

The primary color is set in one place in EmailTemplateBase:
// EmailTemplateBase.cs
private const string PrimaryColor = "#1A56DB";
Change this value and it propagates to every template header, button, and accent element.

Changing email copy

Find the relevant template class, edit the string in RenderContent(). The C# raw string literal ("""...""") makes multi-line HTML easy to write and read. Replace the text-based header in EmailTemplateBase.RenderHeader() with an <img> tag:
// Before:
private string RenderHeader() => $"""
    <div style="background: {PrimaryColor}; padding: 24px; text-align: center;">
        <span style="color: white; font-size: 24px; font-weight: 700;">Acme</span>
    </div>
    """;

// After (host your logo somewhere publicly accessible):
private string RenderHeader() => $"""
    <div style="background: {PrimaryColor}; padding: 24px; text-align: center;">
        <img src="https://cdn.yourdomain.com/logo-white.png"
             alt="Acme" height="32" style="display: block; margin: 0 auto;" />
    </div>
    """;

Adding a new template

Step 1: Add a value to the EmailTemplate enum in Domain:
// src/Acme.Domain/Enums/EmailTemplate.cs
public enum EmailTemplate
{
    // existing values...
    WeeklyDigest,
}
Step 2: Create the template class:
// src/Acme.Infrastructure/Email/Templates/WeeklyDigestTemplate.cs
public class WeeklyDigestTemplate : EmailTemplateBase
{
    private readonly string _userName;
    private readonly int _newProjects;

    public WeeklyDigestTemplate(string userName, int newProjects)
    {
        _userName = userName;
        _newProjects = newProjects;
    }

    protected override string RenderContent()
    {
        return $"""
            <h2 style="color: #1A56DB; font-size: 20px; margin: 0 0 16px;">
                Your weekly digest
            </h2>
            <p style="color: #374151; margin: 0 0 16px;">
                Hi {_userName}, here's what happened this week:
            </p>
            <ul style="color: #374151;">
                <li>{_newProjects} new project(s) created</li>
            </ul>
            """;
    }
}
Step 3: Add a case in ResendEmailService.SendTemplateAsync:
// src/Acme.Infrastructure/Email/ResendEmailService.cs
EmailTemplate.WeeklyDigest => new WeeklyDigestTemplate(
    model.UserName,
    model.NewProjects
),

Testing email rendering locally

Dump a template to HTML and open it in a browser — no SMTP server needed:
// Scratch: add temporarily to any endpoint or test
var template = new WeeklyDigestTemplate("Jane", 3);
var html = template.Render();
await File.WriteAllTextAsync("/tmp/weekly-digest-preview.html", html);
Then open /tmp/weekly-digest-preview.html in your browser. Delete this code before committing. For sends that actually went through, check the Emails tab in the Resend dashboard — it shows the full rendered HTML, delivery timestamp, and open/click events.