# Mail Services
## `MailService`

> [!WARNING]
> The `MailService` and its implementation in `HandlebarsMailService` has been deprecated in favor of the `Mailer` implementation.

The `MailService` class manages **all** emails, and has multiple responsibilities, including formatting, email building (instantiation of ViewModels from variables), and deciding if a mail request should be enqueued or sent directly.

The resulting implementation cannot be owned by a single team (since all emails are in a single class), and as a result, anyone can edit any template without the appropriate team being informed.

To alleviate these issues, all new emails should be implemented using [MJML](../../MailTemplates/README.md) and the `Mailer`.

## `Mailer`

The Mailer feature provides a structured, type-safe approach to sending emails in the Bitwarden server application. It
uses Handlebars templates to render both HTML and plain text email content.

### Architecture

The Mailer system consists of four main components:

1. **IMailer** - Service interface for sending emails
2. **BaseMail<TView>** - Abstract base class defining email metadata (recipients, subject, category)
3. **BaseMailView** - Abstract base class for email template ViewModels
4. **IMailRenderer** - Internal interface for rendering templates (implemented by `HandlebarMailRenderer`)

### How To Use

1. Define a ViewModel that inherits from `BaseMailView` with properties for template data.
2. Define an email class that inherits from `BaseMail<TView>` with metadata like `Subject`.
3. Create Handlebars templates (`.html.hbs` and `.text.hbs`) as embedded resources, preferably using the `MJML` [pipeline](../../MailTemplates/Mjml/README.md#development-process), in
   a directory in `/src/Core/MailTemplates/Mjml`.
4. Use `IMailer.SendEmail()` to render and send the email.

### Creating a New Email

#### Step 1: Define the ViewModel

Create a class that inherits from `BaseMailView`:

```csharp
using Bit.Core.Platform.Mailer;

namespace MyApp.Emails;

public class WelcomeEmailView : BaseMailView
{
    public required string UserName { get; init; }
    public required string ActivationUrl { get; init; }
}
```

#### Step 2: Define the email class

Create a class that inherits from `BaseMail<TView>`:

```csharp
public class WelcomeEmail : BaseMail<WelcomeEmailView>
{
    public override string Subject => "Welcome to Bitwarden";
}
```

#### Step 3: Create Handlebars templates

Create two template files as embedded resources next to your ViewModel.

> [!IMPORTANT]  
> The files must be located directly next to the `ViewClass` and match the name of the view.

**WelcomeEmailView.html.hbs** (HTML version):

```handlebars
<h1>Welcome, {{ UserName }}!</h1>
<p>Thank you for joining Bitwarden.</p>
<p>
    <a href="{{ ActivationUrl }}">Activate your account</a>
</p>
<p><small>&copy; {{ CurrentYear }} Bitwarden Inc.</small></p>
```

**WelcomeEmailView.text.hbs** (plain text version):

```handlebars
Welcome, {{ UserName }}!

Thank you for joining Bitwarden.

Activate your account: {{ ActivationUrl }}

� {{ CurrentYear }} Bitwarden Inc.
```

**Important**: Template files must be configured as embedded resources in your `.csproj`:

```xml

<ItemGroup>
    <EmbeddedResource Include="**\*.hbs" />
</ItemGroup>
```

#### Step 4: Send the email

Inject `IMailer` and send the email, this may be done in a service, command or some other application layer.

```csharp
public class SomeService
{
    private readonly IMailer _mailer;

    public SomeService(IMailer mailer)
    {
        _mailer = mailer;
    }

    public async Task SendWelcomeEmailAsync(string email, string userName, string activationUrl)
    {
        var mail = new WelcomeEmail
        {
            ToEmails = [email],
            View = new WelcomeEmailView
            {
                UserName = userName,
                ActivationUrl = activationUrl
            }
        };

        await _mailer.SendEmail(mail);
    }
}
```

### Advanced Features

#### Multiple Recipients

Send to multiple recipients by providing multiple email addresses:

```csharp
var mail = new WelcomeEmail
{
    ToEmails = ["user1@example.com", "user2@example.com"],
    View = new WelcomeEmailView { /* ... */ }
};
```

#### Bypass Suppression List

For critical emails like account recovery or email OTP, you can bypass the suppression list:

```csharp
public class PasswordResetEmail : BaseMail<PasswordResetEmailView>
{
    public override string Subject => "Reset Your Password";
    public override bool IgnoreSuppressList => true; // Use with caution
}
```

**Warning**: Only use `IgnoreSuppressList = true` for critical account recovery or authentication emails.

#### Email Categories

Optionally categorize emails for processing at the upstream email delivery service:

```csharp
public class MarketingEmail : BaseMail<MarketingEmailView>
{
    public override string Subject => "Latest Updates";
    public string? Category => "marketing";
}
```

### Built-in View Properties

All ViewModels inherit from `BaseMailView`, which provides:

- **CurrentYear** - The current UTC year (useful for copyright notices)

```handlebars

<footer>&copy; {{ CurrentYear }} Bitwarden Inc.</footer>
```

### Template Naming Convention

Templates must follow this naming convention:

- HTML template: `{ViewModelFullName}.html.hbs`
- Text template: `{ViewModelFullName}.text.hbs`

For example, if your ViewModel is `Bit.Core.Auth.Models.Mail.VerifyEmailView`, the templates must be:

- `Bit.Core.Auth.Models.Mail.VerifyEmailView.html.hbs`
- `Bit.Core.Auth.Models.Mail.VerifyEmailView.text.hbs`

## Dependency Injection

Register the Mailer services in your DI container using the extension method:

```csharp
using Bit.Core.Platform.Mailer;

services.AddMailer();
```

Or manually register the services:

```csharp
using Microsoft.Extensions.DependencyInjection.Extensions;

services.TryAddSingleton<IMailRenderer, HandlebarMailRenderer>();
services.TryAddSingleton<IMailer, Mailer>();
```

### Performance Notes

- **Template caching** - `HandlebarMailRenderer` automatically caches compiled templates
- **Lazy initialization** - Handlebars is initialized only when first needed
- **Thread-safe** - The renderer is thread-safe for concurrent email rendering

# Overriding email templates from disk

The mail services support loading the mail template from disk. This is intended to be used by self-hosted customers who want to modify their email appearance. These overrides are not intended to be used during local development, as any changes there would not be reflected in the templates used in a normal deployment configuration.

Any customer using this override has worked with Bitwarden support on an approved implementation and has acknowledged that they are responsible for reacting to any changes made to the templates as a part of the Bitwarden development process. This includes, but is not limited to, changes in Handlebars property names, removal of properties from the ViewModel classes, and changes in template names.  **Bitwarden is not responsible for maintaining backward compatibility between releases in order to support any overridden emails.**