背景
发送在一个系统中现在是不可缺少的一部分了,通常系统内部会建立一套发送邮件机制,类似 abp .net 框架提供的邮件发送功能一样,在需要发送邮件的地方,调用发送邮件的功能,有的系统会将即将发送的邮件先保存到数据库,然后由定时任务不断的从数据库中读取邮件并发送,譬如nop.
我们知道,邮件发送,属于长时间任务,什么意思呢?也就是说,调用邮件发送功能,这个时候,可能会等待一段时间,ui才会有所响应,在发送邮件的时候,系统处于阻塞状态,abp.net就是这样的,尤其是当发送邮件服务器基本信息有误的时候,导致会等待一段时间,ui才会响应。
使用定时任务或后台工作任务可以解决上述问题,这里不做描述。
下面提供另外一种的解决方案,将发送邮件功能脱离系统,使用消息队列方式,也就是说,系统只需向消息队列写消息,而由专门的邮件发送工具或者系统,发送邮件,这样,即使系统所在服务器和邮件发送工具服务器不是同一台电脑,也可以正常使用邮件发送功能。
背景知识:
redis 的使用: http://www.jianshu.com/p/0dd7d722c410
abp.net: http://www.aspnetboilerplate.com/Pages/Documents
使用 abp 提供的邮件发送功能
前提:已经运行redis 服务
使用vs工具新建命令行程序,并引入nuget 包 :abp
根据abp编写规则,我们需要些一个启动模块,代码如下
public class SendMailModule : AbpModule
{
public override void PreInitialize()
{
this.Configuration.Settings.Providers.Add<AppSettingProvider>();
}
public override void Initialize()
{
}
public override void PostInitialize()
{
}
}
为了使用 abp 提供的邮件发送内容,我们需要提供一个简单的设置提供者,即 AppSettingProvider ,该提供者提供了基础的发送邮件服务器信息,实现代码如下
public class AppSettingProvider : SettingProvider
{
/// <summary>
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
{
return new[]
{
new SettingDefinition(EmailSettingNames.Smtp.EnableSsl, "true"),
new SettingDefinition(EmailSettingNames.Smtp.UseDefaultCredentials, "false"),
new SettingDefinition(EmailSettingNames.Smtp.UserName, "自定义账号"),
new SettingDefinition(EmailSettingNames.Smtp.Password, "自定义密码"),
new SettingDefinition(EmailSettingNames.Smtp.Host, "smtp.qq.com(smtp服务器)"),
new SettingDefinition(EmailSettingNames.Smtp.Port, "25(smtp端口)"),
new SettingDefinition(EmailSettingNames.DefaultFromAddress, "自定义邮箱,一定要有这个"),
new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, "自定义显示名称")
};
}
}
现在我们已经有了基础信息,如果使用邮件发送功能呢?代码如下
/// 启动abp并初始化
var startup = AbpBootstrapper.Create<SendMailModule>();
startup.Initialize();
// 测试是否可以正常发送
var emailSender = IocManager.Instance.Resolve<IEmailSender>();
emailSender.Send("接收地址", "主题", "内容");
如果 上述代码正常运行且接收地址收到邮件,则表明我们提供的基础邮件发送服务器信息是正确的。
使用 redis 提供的队列
我们在代码中,引入 redis client的nuget包 StackExchange.Redis
图片.png然后通过代码,建立消息队列通道的监听
var sub = redisClient.GetSubscriber();
sub.Subscribe(
"mailtool",
(channel, message) =>
{
// 假设邮件格式
// 收件人地址#主题#内容
Console.WriteLine(message);
var recMsg = (string)message;
var msg = recMsg.Split('#');
emailSender.Send(msg[0], msg[1], msg[2]);
});
并且,随之通过通道发送一条邮件信息
sub.Publish("mailtool", "目标地址#mailtool测试#我是通过redis 消息队列发出来的");
全部代码如下:
/// <summary>
/// The program.
/// </summary>
internal class Program
{
/// <summary>
/// The redis client.
/// </summary>
private static readonly ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect("localhost");
/// <summary>
/// The main.
/// </summary>
/// <param name="args">
/// The args.
/// </param>
private static void Main(string[] args)
{
var startup = AbpBootstrapper.Create<SendMailModule>();
startup.Initialize();
// 测试是否可以正常发送
var emailSender = IocManager.Instance.Resolve<IEmailSender>();
emailSender.Send("目标地址", "主题", "内容");
var sub = redisClient.GetSubscriber();
sub.Subscribe(
"mailtool",
(channel, message) =>
{
// 假设邮件格式
// 收件人地址#主题#内容
Console.WriteLine(message);
var recMsg = (string)message;
var msg = recMsg.Split('#');
emailSender.Send(msg[0], msg[1], msg[2]);
});
sub.Publish("mailtool", "目标地址#主题#内容");
Console.ReadKey();
}
}
使用 redis 客户端发送邮件
前提,已经打开 redis 客户端,且运行 邮件发送工具 RedisMailTool
输入命令: PUBLISH "mailtool" "目标地址#主题#内容"
图片.png
邮件会成功发送给目标地址
总结
通过上述内容,我们掌握了如何使用redis 提供的消息队列 实现简单的邮件发送工具。
也掌握了如何使用 abp提供的邮件发送功能发送邮件,同时,该案例,可以作为abp开发非web项目的一个启发。
同样的,现在越来越多的系统提供发送手机短信功能,我们是不是也可以借助消息队列手段将该功能单独出一个小工具。
源代码: https://git.oschina.net/zhaord/redismailtool
我的公众号
qq:1260825783
若是需要转载,请备注原地址:http://www.jianshu.com/p/e8f9e46ccc40
网友评论