欢迎光临
我们一直在努力

结合ABP源码实现邮件发送功能

1. 前言

最近pm临时提出了多种邮件验证操作的需求,因为一时间也没有找到好的邮件收发组件,也抱着研究ABP的心态,就花了几小时时间探究了一下ABP中关于Email的处理和操作。其实邮件操作大多大同小异,这次只是希望介绍一下ABP中实现功能的代码结构而已,以下是具体过程

演示的ABP代码版本为0.9.0.0,不过后面版本对于这部分的修改较少,所以完全不影响之后版本的移植使用

 

2. 实现过程

ABP的Mail操作放在了Abp.Net.Mail和Abp.Net.Mail.smtp中,第一步先让我们直接看看这个文件夹下类及接口的代码图(未经允许不可使用)

 

1. 代码图(重)

结合ABP源码实现邮件发送功能

根据代码图可以发现ABP对于Mail处理主要由三部分组成

  • 第一部分是通过继承SettingProvider的EmailSettingProvider来对Mail相关参数进行设置(其中EmailSettingNames定义相关字符串)
  • 第二部分是以IEmailSenderConfiguration接口为基派生出的对SettingProvider设置的邮件参数进行读取和传输的相关操作类
  • 第三部分是以IEmailSender接口为基派生出的Mail发送操作相关类

至于Smtp开头的文件,则是以Smtp形式进行邮件发送的一种实现文件而已,后文也将直接使用该种方式进行处理

 

2.具体实现

在具体的实现上,我发现ABP本身的Mail相关类已经十分完整,只是在邮件参数的配置上需要采取自定义的实现,所以我直接抽取了ABP的源码来进行演示

 

2.1 定义AppSettingNames及AppSettingProvider

AppSettingNames中定义相关的唯一字符串,大家可以认为是Key,而AppSettingProvider中则是将Key对应的邮件参数赋值,供之后的Configuration读取

邮件功能推荐放在Core模块中,完成相关的provider后在CoreModule加入Configuration.Settings.Providers.Add<AppSettingProvider>();即可生效

public static class AppSettings { /// <summary> /// SMTP related email settings. /// </summary> public static class Smtp { /// <summary> /// Abp.Net.Mail.DefaultFromAddress /// </summary> public const string DefaultAddress = "Trucking.Net.Mail.DefaultFromAddress"; /// <summary> /// Abp.Net.Mail.DefaultFromDisplayName /// </summary> public const string DefaultDisplayName = "Trucking.Net.Mail.DefaultFromDisplayName"; /// <summary> /// Abp.Net.Mail.Smtp.Host /// </summary> public const string Host = "Trucking.Net.Mail.Smtp.Host"; /// <summary> /// Abp.Net.Mail.Smtp.Port /// </summary> public const string Port = "Trucking.Net.Mail.Smtp.Port"; /// <summary> /// Abp.Net.Mail.Smtp.UserName /// </summary> public const string UserName = "Trucking.Net.Mail.Smtp.UserName"; /// <summary> /// Abp.Net.Mail.Smtp.Password /// </summary> public const string Password = "Trucking.Net.Mail.Smtp.Password"; /// <summary> /// Abp.Net.Mail.Smtp.Domain /// </summary> public const string Domain = "Trucking.Net.Mail.Smtp.Domain"; /// <summary> /// Abp.Net.Mail.Smtp.EnableSsl /// </summary> public const string EnableSsl = "Trucking.Net.Mail.Smtp.EnableSsl"; /// <summary> /// Abp.Net.Mail.Smtp.UseDefaultCredentials /// </summary> public const string UseDefaultCredentials = "Trucking.Net.Mail.Smtp.UseDefaultCredentials"; } } public class AppSettingProvider : SettingProvider { public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context) { return new[] { new SettingDefinition(AppSettings.Smtp.Host, "smtp.gmail.com", L("SmtpHost"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.Port, "587", L("SmtpPort"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.UserName, "myemail@gmail.com", L("Username"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.Password, "mypassword", L("Password"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.Domain, "", L("DomainName"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.EnableSsl, "true", L("UseSSL"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.UseDefaultCredentials, "false", L("UseDefaultCredentials"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.DefaultAddress, "myemail@gmail.com", L("DefaultEmailAddress"), scopes: SettingScopes.Application | SettingScopes.Tenant), new SettingDefinition(AppSettings.Smtp.DefaultDisplayName, "CompanyName", L("DefaultDisplayName"), scopes: SettingScopes.Application | SettingScopes.Tenant) }; } private static LocalizableString L(string name) { return new LocalizableString(name, AbpConsts.LocalizationSourceName); } }

 

2.2 EmailSenderConfiguration配置

这个类的作用如上面提到的那样,主要是读取自定义的AppSettingProvider中设置的邮件参数值

IUserEmailSenderConfiguration接口略

public class UserEmailSenderConfiguration : TruckingServiceBase, IUserEmailSenderConfiguration, ITransientDependency { /// <summary> /// Gets a setting value by checking. Throws <see cref="AbpException"/> if it's null or empty. /// </summary> /// <param name="name">Name of the setting</param> /// <returns>Value of the setting</returns> protected string GetNotEmptySettingValue(string name) { var value = SettingManager.GetSettingValue(name); if (value.IsNullOrEmpty()) { throw new AbpException(String.Format("Setting value for '{0}' is null or empty!", name)); } return value; } /// <summary> /// SMTP Host name/IP. /// </summary> public string Host { get { return GetNotEmptySettingValue(AppSettings.Smtp.Host); } } /// <summary> /// SMTP Port. /// </summary> public int Port { get { return SettingManager.GetSettingValue<int>(AppSettings.Smtp.Port); } } /// <summary> /// User name to login to SMTP server. /// </summary> public string UserName { get { return GetNotEmptySettingValue(AppSettings.Smtp.UserName); } } /// <summary> /// Password to login to SMTP server. /// </summary> public string Password { get { return GetNotEmptySettingValue(AppSettings.Smtp.Password); } } /// <summary> /// Domain name to login to SMTP server. /// </summary> public string Domain { get { return SettingManager.GetSettingValue(AppSettings.Smtp.Domain); } } /// <summary> /// Is SSL enabled? /// </summary> public bool EnableSsl { get { return SettingManager.GetSettingValue<bool>(AppSettings.Smtp.EnableSsl); } } /// <summary> /// Use default credentials? /// </summary> public bool UseDefaultCredentials { get { return SettingManager.GetSettingValue<bool>(AppSettings.Smtp.UseDefaultCredentials); } } public string DefaultAddress { get { return GetNotEmptySettingValue(AppSettings.Smtp.DefaultAddress); } } public string DefaultDisplayName { get { return SettingManager.GetSettingValue(AppSettings.Smtp.DefaultDisplayName); } } }

 

2.3 SmtpEmailSender实现(Smtp实现邮件发送)

UserSmtpEmailSender类才是真正的对Mail操作类,它通过注入IUserEmailSenderConfiguration接口,读取相关的Mail参数,如Host,UserName,Password等,然后再调用.NET的Mail发送邮件。

IUserSmtpEmailSender接口略

public class UserSmtpEmailSender : IUserSmtpEmailSender, ITransientDependency { private readonly IUserEmailSenderConfiguration _configuration; public UserSmtpEmailSender(IUserEmailSenderConfiguration configuration) { _configuration = configuration; } public async Task SendAsync(string to, string subject, string body, bool isBodyHtml = true) { await SendAsync(_configuration.DefaultAddress, to, subject, body, isBodyHtml); } public void Send(string to, string subject, string body, bool isBodyHtml = true) { Send(_configuration.DefaultAddress, to, subject, body, isBodyHtml); } public async Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true) { await SendAsync(new MailMessage(from, to, subject, body) {IsBodyHtml = isBodyHtml}); } public void Send(string from, string to, string subject, string body, bool isBodyHtml = true) { Send(new MailMessage(from, to, subject, body) {IsBodyHtml = isBodyHtml}); } public async Task SendAsync(MailMessage mail, bool normalize = true) { if (normalize) NormalizeMail(mail); await SendEmailAsync(mail); } public void Send(MailMessage mail, bool normalize = true) { if (normalize) NormalizeMail(mail); SendEmail(mail); } public SmtpClient BuildClient() { var host = _configuration.Host; var port = _configuration.Port; var smtpClient = new SmtpClient(host, port); try { if (_configuration.EnableSsl) smtpClient.EnableSsl = true; if (_configuration.UseDefaultCredentials) { smtpClient.UseDefaultCredentials = true; } else { smtpClient.UseDefaultCredentials = false; var userName = _configuration.UserName; if (!userName.IsNullOrEmpty()) { var password = _configuration.Password; var domain = _configuration.Domain; smtpClient.Credentials = !domain.IsNullOrEmpty() ? new NetworkCredential(userName, password, domain) : new NetworkCredential(userName, password); } } return smtpClient; } catch { smtpClient.Dispose(); throw; } } /// <summary> /// Normalizes given email. /// Fills <see cref="MailMessage.From" /> if it's not filled before. /// Sets encodings to UTF8 if they are not set before. /// </summary> /// <param name="mail">Mail to be normalized</param> protected virtual void NormalizeMail(MailMessage mail) { if ((mail.From == null) || mail.From.Address.IsNullOrEmpty()) mail.From = new MailAddress( _configuration.DefaultAddress, _configuration.DefaultDisplayName, Encoding.UTF8 ); if (mail.HeadersEncoding == null) mail.HeadersEncoding = Encoding.UTF8; if (mail.SubjectEncoding == null) mail.SubjectEncoding = Encoding.UTF8; if (mail.BodyEncoding == null) mail.BodyEncoding = Encoding.UTF8; } protected async Task SendEmailAsync(MailMessage mail) { using (var smtpClient = BuildClient()) { await smtpClient.SendMailAsync(mail); } } protected void SendEmail(MailMessage mail) { using (var smtpClient = BuildClient()) { smtpClient.Send(mail); } } }

 

之后我们只需要再调用该EmailSender的SendAsync,填入对应的参数,亲测有效。如果之后要更换邮件组件,则只需要实现对应的UserLibraryEmailSerder即可。

至此,我们便将ABP中单独的一个邮件功能抽离了出来并做了相关解释,其实只要花点功夫,自己手动剥离代码图也可以理解了。至于一个简单的邮件功能为什么在ABP中要实现得如此复杂,每个程序员有每个程序员的答案,还是继续学习吧

  • 海报
海报图正在生成中...
赞(0) 打赏
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
文章名称:《结合ABP源码实现邮件发送功能》
文章链接:https://www.456zj.com/20790.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址