---
title: "Implementing a Worker Service for Newsletter Service in .NET"  
description: "Sending newsletters is a classic background task. You don’t want email delivery to block HTTP requests, slow down users, or fail silently when traffic spikes. T"  
author: "Anubhav Sharma"  
published: 2026-02-09  
updated: 2026-02-09  
canonical: https://answers.mindstick.com/blog/56/implementing-a-worker-service-for-newsletter-service-in-dot-net  
category: "application"  
tags: ["service", ".net programming", "asp.net", "asp.net mvc"]  
reading_time: 4 minutes  

---

# Implementing a Worker Service for Newsletter Service in .NET

Sending newsletters is a classic **background task**. You don’t want [email delivery](https://www.mindstick.com/forum/159413/an-email-server-returns-smtp-550-errors-how-can-troubleshoot-the-email-delivery-problem) to block [HTTP requests](https://www.mindstick.com/articles/1406/debugging-http-requests-and-http-response), [slow down](https://yourviews.mindstick.com/view/86403/best-healthy-ways-to-slow-down-your-sleep-quota) users, or fail silently when traffic spikes. This is where a **.NET Worker Service** fits perfectly.

In this article, we’ll build a **Newsletter Worker Service** using .NET that runs independently, processes newsletter jobs in the background, and can be hosted as a Windows Service, Linux daemon, or Docker container.

## Why Use a Worker Service for Newsletters?

Sending newsletters inside a controller or API call is risky:

- [Email sending](https://www.mindstick.com/interview/34184/what-is-the-difference-between-synchronous-and-asynchronous-email-sending-in-c-sharp) is slow and I/O heavy
- Failures are hard to retry
- App restarts can interrupt delivery
- Scaling becomes painful

A Worker Service solves this by:

- Running independently of web requests
- Processing jobs asynchronously
- Supporting retries, logging, and graceful shutdown
- Scaling horizontally

## What Is a .NET Worker Service?

A Worker Service is a **long-running background process** built on `IHostedService`.

Typical use cases:

- Email & notification sending
- Queue consumers
- Scheduled jobs
- Data sync
- Report generation

It runs using the **[Generic Host](https://www.mindstick.com/forum/157442/what-is-a-generic-host-in-dot-net-core)**, same infrastructure used by [ASP.NET Core](https://www.mindstick.com/articles/326150/asp-dot-net-core-why-it-is-best-suited-for-banking-and-finance-sectors).

## Architecture Overview

## Simple Newsletter Flow

- Web App stores newsletter job in DB / Queue
- Worker Service polls or listens
- Worker sends emails
- Status updated (Sent / Failed / Retried)

```plaintext
Web App → Database / Queue → Worker Service → SMTP / Email API
```

## Step 1: Create a Worker Service Project

```plaintext
dotnet new worker -n Newsletter.Worker
cd Newsletter.Worker
```

Project structure:

```plaintext
Newsletter.Worker
 ├── Program.cs
 ├── Worker.cs
 ├── appsettings.json
```

## Step 2: Configure the Host

`Program.cs`

```cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
        services.AddSingleton<INewsletterService, NewsletterService>();
    })
    .Build();

await host.RunAsync();
```

## Step 3: Implement the Worker

`Worker.cs`

```cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly INewsletterService _newsletterService;

    public Worker(
        ILogger<Worker> logger,
        INewsletterService newsletterService)
    {
        _logger = logger;
        _newsletterService = newsletterService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Newsletter Worker started.");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await _newsletterService.ProcessPendingNewslettersAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while processing newsletters");
            }

            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
        }

        _logger.LogInformation("Newsletter Worker stopping.");
    }
}
```

## Step 4: Newsletter Service Logic

`INewsletterService.cs`

```cs
public interface INewsletterService
{
    Task ProcessPendingNewslettersAsync(CancellationToken token);
}
```

`NewsletterService.cs`

```cs
public class NewsletterService : INewsletterService
{
    public async Task ProcessPendingNewslettersAsync(CancellationToken token)
    {
        var newsletters = GetPendingNewsletters();

        foreach (var newsletter in newsletters)
        {
            if (token.IsCancellationRequested)
                break;

            try
            {
                await SendEmailAsync(newsletter);
                MarkAsSent(newsletter.Id);
            }
            catch
            {
                MarkAsFailed(newsletter.Id);
            }
        }
    }

    private List<Newsletter> GetPendingNewsletters()
    {
        // Fetch from DB or queue
        return new List<Newsletter>();
    }

    private Task SendEmailAsync(Newsletter newsletter)
    {
        // SMTP / SendGrid / SES logic
        return Task.CompletedTask;
    }

    private void MarkAsSent(int id) { }
    private void MarkAsFailed(int id) { }
}
```

## Step 5: Email Sending Strategy

You can plug in:

- SMTP (`System.Net.Mail`)
- SendGrid
- Amazon SES
- Azure Communication Services

Always:

- Use async APIs
- Set timeouts
- Log failures
- Avoid blocking calls

## Step 6: Configuration via appsettings.json

```plaintext
{
  "Worker": {
    "IntervalSeconds": 30
  },
  "Smtp": {
    "Host": "smtp.example.com",
    "Port": 587,
    "Username": "user",
    "Password": "password"
  }
}
```

Bind configs using `IOptions<T>` for [clean code](https://answers.mindstick.com/qa/111787/what-are-the-key-principles-of-clean-code-and-how-do-they-improve-software-quality).

## Step 7: Logging & Observability

Use [structured logging](https://answers.mindstick.com/blog/38/dot-net-serilog-structured-logging-done-right):

```plaintext
_logger.LogInformation(
    "Sending newsletter {NewsletterId} to {Email}",
    newsletter.Id,
    newsletter.Email);
```

Recommended:

- Serilog
- Seq / ELK
- Application Insights

## Step 8: Graceful Shutdown

Worker services automatically handle shutdown signals:

- `CTRL + C`
- Windows Service stop
- Docker stop

Using `CancellationToken` ensures:

- No half-sent emails
- Clean exit
- No [data corruption](https://answers.mindstick.com/qa/99813/how-to-fix-issues-with-file-or-data-corruption-in-computer-systems)

## Step 9: Deployment Options

You can host the worker as:

- Windows Service
- Linux systemd service
- Docker container
- Kubernetes Job / Deployment
- Azure App Service (Worker)

## Common Enhancements

- Retry policy (Polly)
- Queue-based processing (RabbitMQ, Azure Service Bus)
- Batch sending
- [Rate limiting](https://answers.mindstick.com/qa/112126/how-do-i-implement-rate-limiting-to-prevent-abuse-of-apis)
- Dead-letter handling
- Health checks

## When NOT to Use a Worker Service

- Very small apps with few emails
- Real-time user notifications
- One-off scripts
- In those cases, simpler background jobs may suffice.

## Final Thoughts

A .NET Worker Service is a **clean, scalable, and production-ready** way to handle newsletter delivery. It keeps your web app fast, improves reliability, and gives you full control over retries, failures, and scaling.

---

Original Source: https://answers.mindstick.com/blog/56/implementing-a-worker-service-for-newsletter-service-in-dot-net

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
