NPv.Mail 2.2.0

dotnet add package NPv.Mail --version 2.2.0
                    
NuGet\Install-Package NPv.Mail -Version 2.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NPv.Mail" Version="2.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NPv.Mail" Version="2.2.0" />
                    
Directory.Packages.props
<PackageReference Include="NPv.Mail" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NPv.Mail --version 2.2.0
                    
#r "nuget: NPv.Mail, 2.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NPv.Mail@2.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NPv.Mail&version=2.2.0
                    
Install as a Cake Addin
#tool nuget:?package=NPv.Mail&version=2.2.0
                    
Install as a Cake Tool

NPv.Mail

SMTP delivery and Scriban-based email template rendering for NPv.Mail.Abstractions.

πŸ“Œ Breaking changes

v2.0.0

  • Target framework updated to net10.0 (dropped net9.0 support).

This is a personal library that focuses on the latest .NET runtime to keep maintenance simple and enjoyable.

✨ What this package provides

NPv.Mail is the infrastructure implementation package for the mail contracts from NPv.Mail.Abstractions.

  • πŸ“§ MailKitMailSender β€” sends HTML email through SMTP using MailKit and MimeKit.
  • βš™οΈ Default SMTP settings via IOptions<SmtpSettings> β€” bind one application-level SMTP configuration from IConfiguration.
  • πŸ” Per-call SMTP override β€” send a specific message with explicit SmtpSettings, useful for tenant-specific or customer-specific sender accounts.
  • πŸ“Ž Attachments β€” attach files with file name, byte content, and MIME content type.
  • πŸ“ ScribanEmailTemplateRenderer β€” renders localized embedded HTML templates with Scriban.
  • 🧱 Built-in layout support β€” wraps rendered template content in a localized Layout.html / Layout-{language}.json layout.
  • πŸ”Œ Clean architecture friendly β€” depends on abstractions and is easy to register in DI.

Use this package in your application or infrastructure layer when you need concrete mail delivery and template rendering.

πŸ“¦ Installation

dotnet add package NPv.Mail

The package already references NPv.Mail.Abstractions, so you usually do not need to install it separately unless another project only needs the contracts.

βš™οΈ Configuration

Add SMTP settings to appsettings.json:

{
  "Smtp": {
    "ServerName": "smtp.example.com",
    "ServerPort": 465,
    "UserName": "user@example.com",
    "Password": "yourpassword",
    "FromAddress": "noreply@example.com",
    "FromName": "Example Sender"
  }
}

MailKitMailSender connects with SecureSocketOptions.SslOnConnect, so configure the port expected by your SMTP provider for SSL-on-connect connections.

πŸ”Œ Register services

using NPv.Mail.Abstractions.Sending;
using NPv.Mail.Abstractions.Templating;
using NPv.Mail.Sending;
using NPv.Mail.Templating;

builder.Services.Configure<SmtpSettings>(
    builder.Configuration.GetSection("Smtp"));

builder.Services.AddTransient<IMailSender, MailKitMailSender>();
builder.Services.AddTransient<IEmailTemplateRenderer>(_ =>
    new ScribanEmailTemplateRenderer([typeof(Program).Assembly]));

Pass every assembly that contains your embedded email templates to ScribanEmailTemplateRenderer. The renderer also falls back to the model assembly for model-specific templates and to the NPv.Mail assembly for the built-in layout.

πŸ“§ Send email with default SMTP settings

Use this overload when the message should be delivered through the SMTP settings bound at application startup.

var sender = app.Services.GetRequiredService<IMailSender>();

var message = new MailRequest
{
    To = "recipient@example.com",
    Subject = "Welcome!",
    HtmlBody = "<p>Hello world!</p>",
    Attachments =
    [
        new MailAttachment
        {
            FileName = "hello.txt",
            Content = Encoding.UTF8.GetBytes("Hello world!"),
            ContentType = "text/plain"
        }
    ]
};

await sender.SendAsync(message, CancellationToken.None);

πŸ” Send email with explicit SMTP settings

Use this overload when SMTP settings must be selected dynamically, for example for a specific tenant, customer, mailbox, or one-off delivery configuration.

var smtpSettings = new SmtpSettings
{
    ServerName = "smtp.customer.example.com",
    ServerPort = 465,
    UserName = "customer-sender@example.com",
    Password = "smtp-password",
    FromAddress = "customer-sender@example.com",
    FromName = "Customer Sender"
};

var message = new MailRequest
{
    To = "recipient@example.com",
    Subject = "Welcome!",
    HtmlBody = "<p>Hello from a custom SMTP account.</p>"
};

await sender.SendAsync(smtpSettings, message, CancellationToken.None);

πŸ“ Render localized templates

ScribanEmailTemplateRenderer renders an IEmailTemplateModel by convention:

  • HTML template: {ModelTypeName}.html
  • localization file: {ModelTypeName}-{LanguageCode}.json
  • layout template: Layout.html
  • layout localization file: Layout-{LanguageCode}.json

The model must implement IEmailTemplateModel and provide LanguageCode.

public sealed record ConfirmEmailTemplateModel(
    string ConfirmUrl,
    string LanguageCode) : IEmailTemplateModel;

Example embedded template files:

EmailTemplates/
  ConfirmEmailTemplateModel.html
  ConfirmEmailTemplateModel-en.json

ConfirmEmailTemplateModel-en.json can contain localized strings and Scriban expressions that use model properties:

{
  "subject": "Confirm your email",
  "title": "Welcome!",
  "buttonText": "Confirm email",
  "buttonUrl": "{{ ConfirmUrl }}"
}

ConfirmEmailTemplateModel.html can use both model properties and localized values:

<h1>{{ title }}</h1>
<p>Please confirm your email address.</p>
<a href="{{ buttonUrl }}">{{ buttonText }}</a>

Render the template:

var renderer = app.Services.GetRequiredService<IEmailTemplateRenderer>();

var content = renderer.Render(
    new ConfirmEmailTemplateModel(confirmUrl, "en"));

Console.WriteLine(content.Subject);
Console.WriteLine(content.HtmlBody);

The returned EmailContent contains the rendered subject and final HTML body after the content template has been inserted into the layout.

🧩 Main contracts used by this package

public interface IMailSender
{
    Task SendAsync(SmtpSettings smtpSettings, MailRequest message, CancellationToken cancellationToken);
    Task SendAsync(MailRequest message, CancellationToken cancellationToken);
}
public interface IEmailTemplateRenderer
{
    EmailContent Render<T>(T model) where T : IEmailTemplateModel;
}

Author's Note

This library grew out of my long-standing personal interest in structuring and publishing open source packages. Over time, I’ve revisited and refined earlier internal utilities and ideas, giving them a more consistent shape and preparing them for wider reuse. Along the way, I’ve also taken the opportunity to explore how open source distribution and licensing work in the .NET ecosystem.

It’s a small step toward something I’ve always wanted to try β€” sharing practical, minimal tools that reflect years of learning, experimentation, and refinement.

Hopefully, someone finds it useful.

Nikolai πŸ˜›

βš–οΈ License

MIT β€” free for commercial and open-source use.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.2.0 55 7/2/2026
2.1.1 609 4/22/2026
2.1.0 759 3/24/2026
2.0.3 643 3/7/2026
2.0.2 5,049 2/1/2026
2.0.1 12,801 12/24/2025
2.0.0 12,785 12/24/2025
1.0.3 14,784 9/13/2025
1.0.2 14,772 9/13/2025
1.0.1 14,763 9/13/2025
1.0.0 14,795 9/10/2025