# Att lägga till bakgrund för att skicka e-mail

<!--category-- ASP.NET -->
<datetime class="hidden">2024-08-07T08:15</datetime>

##Introduction

I min tidigare post förklarade jag hur man skickar e-mail med FluentEmail och den SMTP-clienten. Men ett problem med detta är att de skjuter upp sändningen av e-poster . SMTP serverr tenderar att vara långsamma och kan ta ett tag för att skicka e-Mails. Det kan vara irriterande för kunderna och kännas som en logjam i din application

Ett sätt att komma runt detta är att skicka e-mail i bakgrunden. På det viset kan användaren fortsätta använda applikationen utan att behöva vänta på att e-posten ska skickas

[TOC]

## Agtergrond-Optioner i ASP.NET Core

I ASP.NET Core har du två huvudsakliga möjligheter (över mer avancerade möjligheter som Hangfire / QuartzM SK3

- IHostedService - den här volymen ger dig grundläggande livscykelanalys för dina bakgrundsuppgifter . Du kan starta och stanna upp servicen och den kommer att fungera i bakgrunden
- IHostedLifetime - den här volymen ger dig mer kontroll över livscykeln av dina bakgrundsuppgifter . Du kan också starta och stoppa applikationen och den kommer att köra i bakgrunden men du har mer kontroll när du startar , stannar M SK3 startar~

I detta exempel använder jag en enkel IHostedService för att skicka e-post i bakgrunden.

## källkod

Den kompletta källan för detta är under

<details>
<summary>Background Email Service</summary>

```csharp
using System.Threading.Tasks.Dataflow;
using Mostlylucid.Email.Models;

namespace Mostlylucid.Email
{
    public class EmailSenderHostedService(EmailService emailService, ILogger<EmailSenderHostedService> logger)
        : IHostedService, IDisposable
    {
        private readonly BufferBlock<BaseEmailModel> _mailMessages = new();
        private Task _sendTask = Task.CompletedTask;
        private CancellationTokenSource cancellationTokenSource = new();

        public async Task SendEmailAsync(BaseEmailModel message)
        {
            await _mailMessages.SendAsync(message);
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Starting background e-mail delivery");
            // Start the background task
            _sendTask = DeliverAsync(cancellationTokenSource.Token);
            return Task.CompletedTask;
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Stopping background e-mail delivery");

            // Cancel the token to signal the background task to stop
            await cancellationTokenSource.CancelAsync();

            // Wait until the background task completes or the cancellation token triggers
            await Task.WhenAny(_sendTask, Task.Delay(Timeout.Infinite, cancellationToken));
        }

        private async Task DeliverAsync(CancellationToken token)
        {
            logger.LogInformation("E-mail background delivery started");

            while (!token.IsCancellationRequested)
            {
                BaseEmailModel? message = null;
                try
                {if(_mailMessages.Count == 0) continue;
                    message = await _mailMessages.ReceiveAsync(token);
                    switch (message)
                    {
                        case ContactEmailModel contactEmailModel:
                            await emailService.SendContactEmail(contactEmailModel);
                            break;
                        case CommentEmailModel commentEmailModel:
                            await emailService.SendCommentEmail(commentEmailModel);
                            break;
                    }
                    logger.LogInformation("Email from {SenderEmail} sent", message.SenderEmail);
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception exc)
                {
                    logger.LogError(exc, "Couldn't send an e-mail from {SenderEmail}", message?.SenderEmail);
                    await Task.Delay(1000, token); // Delay and respect the cancellation token
                    if (message != null)
                    {
                        await _mailMessages.SendAsync(message, token);
                    }
                }
            }

            logger.LogInformation("E-mail background delivery stopped");
        }

        public void Dispose()
        {
            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
        }
    }
}
```

</details>
Här kan ni se att vi hanterar serviceuppstartningen och konfigurerar en ny BufferBlock för att hålla e-posten.

```csharp
public class EmailSenderHostedService(EmailService emailService, ILogger<EmailSenderHostedService> logger)
        : IHostedService, IDisposable
    {
        private readonly BufferBlock<BaseEmailModel> _mailMessages = new();
        private Task _sendTask = Task.CompletedTask;
        private CancellationTokenSource cancellationTokenSource = new();
```

Vi ordnade också en ny uppgift för att leverera e-posterna i bakgrunden.
och en CancellationTokenSource för att avbryta uppgiften graciöst när vi vill stanna upp servicen.

Sedan driver vi upp HostedService med StartAsync och ger ingångspunkten till andra tjänster för att skicka ett e-mail.

```csharp
 public async Task SendEmailAsync(BaseEmailModel message)
        {
            await _mailMessages.SendAsync(message);
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Starting background e-mail delivery");
            // Start the background task
            _sendTask = DeliverAsync(cancellationTokenSource.Token);
            return Task.CompletedTask;
        }
```

I vår Konfigurationsklass behöver vi nu registrera nkonzoet med DI-containern och starta HostedService

```csharp
       services.AddSingleton<EmailSenderHostedService>();
        services.AddHostedService(provider => provider.GetRequiredService<EmailSenderHostedService>());
```

Nu kan vi skicka e-post i bakgrunden genom att ringa SendEmailAsync-metoden på EmailSenderHostedService.
e.g., för Kontaktformularet gör vi detta

```csharp
            var contactModel = new ContactEmailModel()
            {
                SenderEmail = user.email,
                SenderName =user.name,
                Comment = commentHtml,
            };
            await sender.SendEmailAsync(contactModel);
```

I koden ovanför lägger det här meddelandet till vår `BufferBlock<BaseEmailModel>` _mailMessages och bakgrundsuppgiften kommer att plocka upp det och skicka ett e-mail.

```csharp
   private async Task DeliverAsync(CancellationToken token)
        {
          ...

            while (!token.IsCancellationRequested)
            {
                BaseEmailModel? message = null;
                try
                {if(_mailMessages.Count == 0) continue;
                    message = await _mailMessages.ReceiveAsync(token);
                    switch (message)
                    {
                        case ContactEmailModel contactEmailModel:
                            await emailService.SendContactEmail(contactEmailModel);
                            break;
                        case CommentEmailModel commentEmailModel:
                            await emailService.SendCommentEmail(commentEmailModel);
                            break;
                    }
                    logger.LogInformation("Email from {SenderEmail} sent", message.SenderEmail);
           ...
            }

            logger.LogInformation("E-mail background delivery stopped");
        }
```

Detta kommer sedan att loopa fram tills vi slutar servicen och fortsätter att övervaka BufferBlock för nya e-mail att skicka