Додання фонового відправлення для е-мейлів (Українська (Ukrainian))

Додання фонового відправлення для е-мейлів

Wednesday, 07 August 2024

//

4 minute read

##Введення

У своєму попередньому пості я описав, як надсилати електронні листи за допомогою FluentEmail і SMTP Client. Однак, однією з проблем з цим є затримка надсилання електронних листів . Сервери SMTP мають тенденцію бути повільними і можуть зайняти деякий час, щоб надіслати електронні листи МSK2 Це може бути неприємно для користувачів та відчувати себе як логам у вашій програміM SK3

Один із способів подолати це - надсилати електронні листи у фоні.. Таким чином пользователь може продовжувати використовувати додаток, не мусив чекати, поки його відправлять.

Опції в основі ASP.NET

В ASP.NET Core ви маєте дві головні варіанти ( окрім більш заawansованих варіантів, таких як Hangfire / QuartzM SK3

  • IHostedService - ця опція дає вам базове управління життєвим циклом для ваших фонових задач . Ви можете запустити і зупинити службу, і вона буде працювати в фоні
  • IHostedLifetime - ця опція дає вам більше контролю над життєвим циклом ваших задач у фоні . Ви також можете запустити і зупинити службу, і вона буде працювати в фоні, але ви маєте більше контролю, коли запускаєш МSK2 зупиняєшся МСК3 запускає М СК4 зупинює і т.д.

У цьому прикладі я' використаю просту IHostedService, щоб надсилати електронні листи у фоні

Источник

Полне джерело для цього є внизу.

Background Email Service
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();
        }
    }
}
Тут ви бачите, що ми маємо справу з запуском сервісу і створенням нового BufferBlock для зберігання електронних листів.
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();

Ми також створили нову задачу для доставки електронних листів у фоні. і CancellationTokenSource, щоб скасувати задачу граційно, коли ми хочемо зупинити службу.

Потім ми запускаємо HostedService з StartAsync і забезпечуємо вхідним пунктом для інших послуг, щоб відправити електронну пошту.

 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;
        }

У нашому класі Налагодження ми тепер маємо зареєструвати службу з контейнером DI і розпочати ХостингСервіс .

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

Тепер ми можемо надсилати електронні листи в фоні, використовуючи метод SendEmailAsync на EmailSenderHostedService. e.gM SK1 для контактного бланка ми робимо це

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

В коді вище це додає це повідомлення до нашого BufferBlock<BaseEmailModel> _mailMessages і фонова задача візьмуть його і відправлять повідомлення.

   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");
        }

Це буде повторюватися, доки ми не зупинимо службу і не продолжимо перевіряти BufferBlock для нових повідомлень.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.