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.json
对 Abp.Mailing.Smtp.Password
进行设置,如下所示:
...
"Settings": {
...
"Abp.Mailing.Smtp.Password": "3zil2vJ325s+uboMEiKCDA==",
...
},
...
拓展:
有关加密知识,参见Abp官方文档 https://docs.abp.io/en/abp/latest/String-Encryption