> ## 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.

# Customizing Email Templates

> Change copy, update brand colors, add a logo, and create new email templates.

## 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:

```csharp theme={null}
// 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`:

```csharp theme={null}
// 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.

## Adding a logo

Replace the text-based header in `EmailTemplateBase.RenderHeader()` with an `<img>` tag:

```csharp theme={null}
// 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`:

```csharp theme={null}
// src/Acme.Domain/Enums/EmailTemplate.cs
public enum EmailTemplate
{
    // existing values...
    WeeklyDigest,
}
```

**Step 2:** Create the template class:

```csharp theme={null}
// 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`:

```csharp theme={null}
// 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:

```csharp theme={null}
// 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.
