首页 > 解决方案 > 作为启动配置过程的一部分,您如何发送电子邮件?

问题描述

作为此测试的一部分,我希望我的应用程序在首次启动并将启动电子邮件发送到某个位置时电子邮件凭据是否有效。

当我在启动甚至 SendGrid 中放置电子邮件功能时,如果凭据有效,则没有错误,但没有发送消息。我可以将其作为中间件过滤器的一部分和缓存的一部分来执行,但这实际上是我的首选,它实际上成为了一个作用域服务。

我的电子邮件代码作为控制器或服务调用的一部分工作,但即使在凭据有效的情况下它不会在启动时出错,但电子邮件实际上并没有发送。

启动.cs

public void ConfigureServices(IServiceCollection services)
{
    var emailStatus = new EmailStatus();

    try
        {
            _emailSender.SendEmailAsync(Options.Support, "App STARTUP",
                   $"email success.");
            emailStatus.failed = false;
            //Set
        }
        catch (SmtpCommandException ex)
        {
            _logger.LogError(ex.Message);
            emailStatus.failed = false;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message);

            // Debug.WriteLine("Exception: " + ex.Message);
            _logger.LogError("Task Inner Exception: " + ex.InnerException);
            _logger.LogError("Task StackTrace: " + ex.StackTrace);
            emailStatus.failed = false;
        }

      services.AddSingleton(emailStatus);
}

电子邮件发件人.cs

public class EmailSender : IEmailSender
{
    public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
    {
        Options = optionsAccessor.Value;
    }

    public EmailSender(AuthMessageSenderOptions options)
    {
        this.Options = options;

    }
    public AuthMessageSenderOptions Options { get; } //set only via Secret Manager

    public Task SendEmailAsync(string email, string subject, string message)
    {
        return Execute(subject, message, email);
    }

    public async Task Execute(string subject, string message, string email)
    {
        if (Options.Service != "SendGrid")
        {
            var mailMessage = new MimeMessage();
            mailMessage.To.Add(new MailboxAddress(email));
            mailMessage.From.Add(new MailboxAddress("noreply@email.com"));


            mailMessage.Subject = subject;
            mailMessage.Body = new TextPart(TextFormat.Html)
            {
                Text = message
            };
            // mailMessage.Body = message;
            //Be careful that the SmtpClient class is the one from Mailkit not the framework!
            using (var emailClient = new SmtpClient())
            {
                //The last parameter here is to use SSL (Which you should!)
                await emailClient.ConnectAsync(Options.Domain, Options.Port, true);

                //Remove any OAuth functionality as we won't be using it. 
                emailClient.AuthenticationMechanisms.Remove("XOAUTH2");

                emailClient.Authenticate(Options.SendGridUser, Options.SendGridKey);

                try
                {
                    await emailClient.SendAsync(mailMessage).ConfigureAwait(false);
                    await emailClient.DisconnectAsync(true).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await emailClient.DisconnectAsync(true).ConfigureAwait(false);
                    throw ex;
                    // return BadRequest(new { message = "Email failed to send", error = ex.ToString() });
                    // Label1.Text = ex.ToString();
                }
                // emailClient.Disconnect(true);
            }
        }
        else
        {

            var client = new SendGridClient(Options.SendGridKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("noreply@email.com", "Do Not Reply"),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);

            await client.SendEmailAsync(msg);
        }
    }
}

标签: c#emailasp.net-core.net-core

解决方案


考虑使用一个IHostedService

创建将作为启动过程的一部分启动的托管服务

public class StartupEmailHostedService : IHostedService {
    private readonly IEmailSender emailSender;
    private readonly ILogger logger;
    private EmailStatus emailStatus;

    public StartupEmailHostedService(IEmailSender emailSender, EmailStatus emailStatus, ILogger<StartupEmailHostedService> logger) {
        this.services = services;
        this.logger = logger;
        this.emailStatus = emailStatus;
    }

    public async Task StartAsync(CancellationToken cancellationToken) {
        try {
            await emailSender.SendEmailAsync(Options.Support, "App STARTUP", $"email success.");
            emailStatus.failed = false;
        } catch (SmtpCommandException ex) {
            logger.LogError(ex.Message);
            emailStatus.failed = true;
        } catch (Exception ex) {
            logger.LogError(ex.Message);
            logger.LogError("Task Inner Exception: " + ex.InnerException);
            logger.LogError("Task StackTrace: " + ex.StackTrace);
            emailStatus.failed = true;
        };
    }

    public Task StopAsync(CancellationToken cancellationToken) {
        return Task.CompletedTask;
    }
}

现在确保在启动时将所有内容都注册到服务集合中。

public void ConfigureServices(IServiceCollection services) {

    //...assuming other dependencies

    services.AddTransient<IEmailSender, EmailSender>();
    services.AddSingleton<EmailStatus>();
    services.AddHostedService<StartupEmailHostedService>();
}

当托管服务启动时,将调用电子邮件逻辑以及所需的功能。

尝试在 Startup 中处理所有这些横切关注点是不必要的,并且可能会导致启动本身出现问题,因为它只是充当引导程序并连接应用程序执行其功能所需的内容。


推荐阅读