Abp vNext : 使用邮件

https://docs.abp.io/en/abp/latest/Emailing

使用邮件

第一步:在项目中已入如下包:

    <PackageReference Include="Volo.Abp.Emailing" Version="6.0.1" />
    <PackageReference Include="Volo.Abp.MailKit" Version="6.0.1" />

添加模块依赖

namespace AbpManaul
{
    [DependsOn(
        ...
        typeof(AbpEmailingModule),
        typeof(AbpMailKitModule)
    )]
    public class AbpManualApplicationModule : AbpModule
    {
    }
}

第二步:使用 appsettings.json 存储配置项,如下所示
代码清单:AbpManual.Web/appsettings.json

{ 
  ...
  "Settings": {
    "Abp.Mailing.Smtp.Host": "smtp.126.com",
    "Abp.Mailing.Smtp.Port": "25",
    "Abp.Mailing.Smtp.UserName": "abpdev",
    "Abp.Mailing.Smtp.Password": "rHGKfmXnrF7p8uZovp2I6A==", // 原值:123, 是邮箱smtp服务的授权码
    "Abp.Mailing.Smtp.Domain": "",
    "Abp.Mailing.Smtp.EnableSsl": "false",
    "Abp.Mailing.Smtp.UseDefaultCredentials": "false",
    "Abp.Mailing.DefaultFromAddress": "abpdev@126.com",
    "Abp.Mailing.DefaultFromDisplayName": "Abp 手册"
  },
  "StringEncryption": {
    "DefaultPassPhrase": "DOKIDhw8UbBTB82G" //Default password to encrypt/decrypt texts
  }

}

StringEncryption 参数见:
https://docs.abp.io/en/abp/latest/String-Encryption

特别注意:
Abp.Mailing.Smtp.Password 必须是一个加密值, 不能使用原值,否则抛如下异常,

 The input data is not a complete block.
System.Security.Cryptography.CryptographicException: The input data is not a complete block.
   at Internal.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at Internal.Cryptography.UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.ReadAsyncCore(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken, Boolean useAsync)

如何根据密码的原值得到加密值,见下一节:加密 SMTP 密码

Tips:如何邮箱申请开通smtp服务
先去邮箱平台申请一个邮箱,然后申请开通smtp服务,
这我使用的是126邮箱,Abp.Mailing.Smtp.Password 的原值不是邮箱的登录密码,
而是申请开通smtp服务成功后,得到的一个授权码

第三步:发送邮件

using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing;

namespace AbpManual.BackgroundJobs
{
    /// <summary>
    /// https://docs.abp.io/zh-Hans/abp/latest/Background-Jobs
    /// 后台作业是一个实现IBackgroundJob<TArgs>接口或继承自BackgroundJob<TArgs>类的类
    /// </summary>
    public class EmailSendingJob : AsyncBackgroundJob<EmailSendingArgs>, ITransientDependency
    {
        private readonly IEmailSender _emailSender;
        private readonly ILogger<EmailSendingJob> _logger;

        public EmailSendingJob(
            IEmailSender emailSender,
            ILogger<EmailSendingJob> logger)
        {
            _emailSender = emailSender;
            _logger = logger;
        }

        public override  async Task ExecuteAsync(EmailSendingArgs args)
        {
            // 模拟随机产生异常,看看后台作业是否因失败再次执行
            if (RandomHelper.GetRandom(0, 10) < 5)
            {
                throw new ApplicationException("A sample exception from the EmailSendingJob!");
            }

            _logger.LogInformation($"############### EmailSendingJob: 邮件已成功发送至邮箱:{args.EmailAddress} ###############");

            //lock (Console.Out)
            //{
            //    var oldColor = Console.ForegroundColor;
            //    Console.ForegroundColor = ConsoleColor.Green;

            //    Console.WriteLine();
            //    Console.WriteLine($"############### EmailSendingJob: 邮件已成功发送至邮箱:{args.EmailAddress} ###############");
            //    Console.WriteLine();

            //    Console.ForegroundColor = oldColor;
            //}

            // 发送邮件
            await _emailSender.SendAsync(
               args.EmailAddress,
               args.Subject,
               args.Body
           );
        }
    }
}

第四步:测试
编辑测试服务
代码清单:AbpManual.Application/BackgroundJobs/BackgroundJobService.cs

using AbpManual.BackgroundJobs;
using Volo.Abp.Application.Services;
using Volo.Abp.BackgroundJobs;

namespace AbpManaul.BackgroundJobs
{
    public class BackgroundJobService : ApplicationService, IBackgroundJobService
    {
        /// <summary>
        /// 默认后台作业管理器
        /// https://docs.abp.io/zh-Hans/abp/latest/Background-Jobs
        /// ABP framework 包含一个简单的 IBackgroundJobManager 实现;
        /// </summary>
        private readonly IBackgroundJobManager _backgroundJobManager;

        public BackgroundJobService(IBackgroundJobManager backgroundJobManager)
        {
            _backgroundJobManager = backgroundJobManager;
        }

        public async Task RegisterAsync(RegisterInput input)
        {
            //TODO: 创建一个新用户到数据库中...

            await _backgroundJobManager.EnqueueAsync(
                new EmailSendingArgs
                {
                    EmailAddress = input.EmailAddress,
                    Subject = "You've successfully registered!",
                    Body = "恭喜你注册成功!"
                }
            );
        }
    }

    public class RegisterInput
    {
        public string Name { get; set; }
        public string EmailAddress { get; set; }
        public string Password { get; set; }
    }
}

点击执行按钮,邮件发送成功,如下图所示:

邮件内容也正确:

加密 SMTP 密码

Abp.Mailing.Smtp.Password 必须是一个加密值。如果你使用 ISettingManager 设置密码,你不必担心。它在内部加密 set 上的值并在 get 上解密。
如果使用 appsettings.json 存储密码,则应手动注入 ISettingEncryptionService 并使用其 Encrypt 方法获取加密值。这可以通过在你的应用程序中创建一个简单的代码来完成。然后你可以删除代码。
更好的做法是,你可以在应用程序中创建一个 UI 来配置电子邮件设置。在这种情况下,你可以直接使用 ISettingManager 而不用担心加密。

定义一个函数,获取加密后的密码,如下所示:

using Volo.Abp.Emailing;
using Volo.Abp.Settings;

namespace AbpManaul.Application.Settings;

public class SettingService
{
    private readonly ISettingEncryptionService _settingEncryptionService;
    private readonly ISettingDefinitionManager _settingDefinitionManager;

    public SettingService(
            ISettingEncryptionService settingEncryptionService,
            ISettingDefinitionManager settingDefinitionManager)
    {
        _settingEncryptionService = settingEncryptionService;
        _settingDefinitionManager = settingDefinitionManager;
    }

    public string EncryptMailingSmtpPassword(string passsword)
    {

        var setting = _settingDefinitionManager.Get(EmailSettingNames.Smtp.Password);
        var encryptPassword = _settingEncryptionService.Encrypt(setting, passsword);

        return encryptPassword;
    }
}

然后调用函数EncryptMailingSmtpPassword(),获取加密后的密码,比如:
调用函数EncryptMailingSmtpPassword(123) 返回 "3zil2vJ325s+uboMEiKCDA=="
然后在使用该值在配置文件 appsettings.jsonAbp.Mailing.Smtp.Password 进行设置,如下所示:

...
  "Settings": {
    ...
    "Abp.Mailing.Smtp.Password": "3zil2vJ325s+uboMEiKCDA==",
    ...
  },
...

拓展:
有关加密知识,参见Abp官方文档 https://docs.abp.io/en/abp/latest/String-Encryption

posted @ 2022-11-13 13:13  easy5  阅读(560)  评论(2)    收藏  举报