Dloizides.Marketing.AspNetCore 1.0.1

dotnet add package Dloizides.Marketing.AspNetCore --version 1.0.1
                    
NuGet\Install-Package Dloizides.Marketing.AspNetCore -Version 1.0.1
                    
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="Dloizides.Marketing.AspNetCore" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dloizides.Marketing.AspNetCore" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Dloizides.Marketing.AspNetCore" />
                    
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 Dloizides.Marketing.AspNetCore --version 1.0.1
                    
#r "nuget: Dloizides.Marketing.AspNetCore, 1.0.1"
                    
#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 Dloizides.Marketing.AspNetCore@1.0.1
                    
#: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=Dloizides.Marketing.AspNetCore&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Dloizides.Marketing.AspNetCore&version=1.0.1
                    
Install as a Cake Tool

Marketing.AspNetCore

Self-hosted marketing / bulk email for .NET. Send one campaign to many recipients over any IEmailService transport (Email.Abstractions) — today that's Maddy/SMTP via Email.Smtp; tomorrow it could be a dedicated bulk ESP (Postal, Mailgun, SES) with no code change. No third-party service is required.

It deliberately stays out of the transactional path: marketing mail is best-effort, rate-limited, carries one-click unsubscribe, and logs its own observability tokens.

What it gives you

  • ICampaignEmailSender.SendBulkAsync(content, recipients) — renders and sends per-recipient mail; one failure never aborts the batch; returns a CampaignSendReport (sent / failed counts + per-recipient failures).
  • Per-recipient merge fields{{firstName}} placeholders in the subject and body, substituted from each recipient's values (HTML-encoded in the body).
  • RFC 8058 one-click unsubscribe — when a recipient has an UnsubscribeUrl, it is rendered in the footer and advertised via List-Unsubscribe / List-Unsubscribe-Post headers.
  • IUnsubscribeTokenService — HMAC-signed, self-contained unsubscribe tokens so the unsubscribe endpoint can be anonymous yet tamper-proof (no session, no DB lookup to verify).
  • Rate limiting — paces the send to MaxSendsPerSecond so it doesn't overwhelm the SMTP relay.
  • Observability — emits campaign_sent / campaign_failed structured logs (the marketing siblings of email_sent / email_failed).

Register

// 1. A transport (any IEmailService) — e.g. SMTP via Email.Smtp:
services.AddSmtpEmail(o => configuration.GetSection("Smtp").Bind(o));

// 2. Marketing on top of it:
services.AddMarketingEmail(configuration);          // binds the "Marketing" section
// or
services.AddMarketingEmail(o =>
{
    o.UnsubscribeSigningKey = "...";                // a server secret
    o.DefaultFromAddress    = "noreply@dloizides.com";
    o.DefaultFromName       = "Acme";
    o.MaxSendsPerSecond     = 10;
    o.FooterText            = "Acme Ltd · 1 Example St · Unsubscribe any time.";
});

Send a campaign

var token = unsubscribeTokens.Create(tenantId, subscriber.Id, subscriber.Email);
var recipient = new CampaignRecipient
{
    Address        = subscriber.Email,
    Name           = subscriber.Name,
    MergeFields    = new Dictionary<string,string> { ["firstName"] = subscriber.FirstName },
    UnsubscribeUrl = $"https://notification-api.dloizides.com/api/v1/marketing/unsubscribe?token={token}",
};

var report = await campaignSender.SendBulkAsync(
    new CampaignContent
    {
        CampaignName = "June newsletter",
        Subject      = "Hi {{firstName}}, what's new",
        HtmlBody     = "<p>Hello {{firstName}},</p><p>...</p>",
    },
    new[] { recipient });

// report.SentCount / report.FailedCount / report.Failures

Unsubscribe endpoint (host side)

if (unsubscribeTokens.TryValidate(token, out var payload))
{
    // payload.TenantId / payload.SubscriberId / payload.Email — mark unsubscribed
}

Configuration (Marketing section)

Key Default Notes
UnsubscribeSigningKey (empty) Required to mint tokens. Keep secret; rotating invalidates old links.
DefaultFromAddress noreply@localhost Fallback sender.
DefaultFromName Marketing Fallback sender name.
ReplyTo (none) Optional default Reply-To.
BrandName / LogoUrl (none) Email shell header.
FooterText (generic) Compliance/postal footer line.
MaxSendsPerSecond 10 <= 0 disables pacing.

MIT.

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
1.0.1 126 7/12/2026