使用Akka Http,ActiveMQ搭建一个邮件发送服务器
2015-08-13 13:25
561 查看
代码地址:https://github.com/yangbajing/scala-applications/tree/master/email-server
应用功能是实现一个基于队列的邮件发送服务,每个邮件发送者(使用smtp协议)作为一个
邮件内容可以通过
推荐在启动时使用
编译与运行:
测试REST服务:
应用功能是实现一个基于队列的邮件发送服务,每个邮件发送者(使用smtp协议)作为一个
sender。多个
sender可以在同一个组
(group)中,每个组中的
sender将串行发送邮件。
邮件内容可以通过
REST API提交,以可以使用
JMS发布到
ActiveMQ中,邮件服务器将从中读取邮件内容。
快速开始
配置:推荐在启动时使用
-Dapplication.file=/usr/app/etc/emailserver/application.conf指定配置文件
[code=language-json]emailserver { server { interface = "0.0.0.0" port = 9999 } emails { email1 { userName = "email1@email.com" password = "" smtp = "" smtpPort = 0 ssl = true # 同一个组内的邮件会串行发送,此key可忽略 group = "1" } email2 { userName = "email2@email.com" password = "" smtp = "" smtpPort = 0 ssl = true group = "2" } } activemq { url = "tcp://127.0.0.1:61616" emailQueueName = "EmailQueue" } }
emails定义邮件发送者(可用于
stmp服务进行邮件发送的邮箱信息)。可以定义多个邮件发送者,但每个邮件发送者的
key不能相同。比如:
email1和
email2
activemq定义了
ActiveMQ服务的连接参数。
编译与运行:
# 编译 ./sbt assembly # 运行 java -Dapplication.file=/usr/app/etc/emailserver/application.conf -jar target/scala-2.11/email-server.jar
测试REST服务:
# 查询存在的邮箱发送者: curl http://localhost:9999/email/users # 发送测试邮件 curl -v -XPOST -H "Content-Type: application/json" \ -d '{"sender":"Info@email.cn", "subject":"测试邮件","to":["user1@email.cn", "user2@email.cn"],"content":"测试邮件内容咯~"}' \ http://localhost:9999/email/send[/code] 使用JMS发送邮件:
安装activemqDownloads:http://mirrors.hust.edu.cn/apache/activemq/5.11.1/apache-activemq-5.11.1-bin.tar.gz tar zxf ~/Downloads/apache-activemq-5.11.1-bin.tar.gz cd apache-activemq-5.11.1/ ./bin/activemq-admin startactivemq管理控制台地址:http://localhost:8161/admin/,账号:admin,密码:admin。
JMS TCP地址:tcp://localhost:61616
生产测试邮件
修改EmailProducers.scala的activeMqUrl及mapMessage参数,运行EmailProducers生产一个邮件发送请求。Akka Http
Akka Http是一个完整的server和client端HTTP开发栈,基于akka-actor他akka-stream。它不是一个WEB框架,而是提供了可以构建Http服务的工具包。Akka Http有一套很直观的DSL来定义路由,自然的形成了一个树型的路由结构。如Routes:[code=language-scala]pathPrefix("email") { path("send") { post { entity(as[JsValue].map(_.as[SendEmail])) { sendEmail => onComplete(emailService.sendEmail(sendEmail)) { case Success(value) => value match { case Right(msg) => complete(msg) case Left(msg) => complete(StatusCodes.Forbidden, msg) } case Failure(e) => complete(StatusCodes.InternalServerError, "SendEmail an error occurred: " + e.getMessage) } } } } ~ path("users") { get { onComplete(emailService.getEmailSenders) { case Success(emailSenders) => complete(Json.toJson(emailSenders)) case Failure(e) => complete(StatusCodes.InternalServerError, "An error occurred: " + e.getMessage) } } } }path->post->entity->complete式的函数嵌套,很直观的定义出了声明式的树型REST URI结构,层次分明、逻辑清晰。entity函数用于解析Http Body,将其映射成希望的数据类型,可自定义映射方法。onComplete函数用在返回类型是一个Future[T]时,提供了快捷的方式把一个Future[T]类型的响应转换到complete。邮件发送
邮件的发送采用了串行发送的方式,这个模式刚好契合Actor默认邮箱的FIFO处理形式。把收到的邮件发送请求告诉一个actor,actor再从邮箱里取出,并组装成XXXXEmail(邮件发送使用了commons-email)后发送出去。
首先,程序将收到的邮件发送请求交给EmailMaster,EmailMaster再根据邮件发送者(连接SMTP的邮箱用户名)来决定将这个发送请求交给哪一个具体的EmailGroupActor。
这里,程序对邮件发送者(简称:sender)做了一个分组。因为对于使用相同smtp邮件发送服务提供的sender,程序中最后对此类的sender做串行发送。而对于不同smtp邮件发送服务提供的sender,我们可以并发的发送邮件。这个可以通过在定义配置文件的时候指定特定sender属于的邮件发送组。[code=language-HOCON] emails { email1 { userName = "email1@email.com" password = "" smtp = "" smtpPort = 0 ssl = true # 同一个组内的邮件会串行发送,此key可忽略 group = "1" } }连接
连接ActiveMQActiveMQ使用了JMS协议,这是一个Java EE标准实现的消息队列。代码在:MQConsumerService。
在JMS里,邮件使用MapMessage消息发送,程序使用case match来匹配期望的消息格式。[code=language-scala]val listener = new MessageListener { override def onMessage(message: Message): Unit = message match { case msg: MapMessage => { val subject = msg.getString("subject") val sender = msg.getString("sender") val content = msg.getString("content") val to = msg.getString("to").split(";") val mimeType = Option(msg.getString("mimeType")).map(MimeType.withName).getOrElse(MimeType.Text) val sendEmail = SendEmail(sender, subject, to, content, None, mimeType) emailService.sendEmail(sendEmail).onComplete(result => logger.debug(result.toString)) }总结
本文简单的演示了Akka Http构建一个REST服务,并支持连接JMS Server来获取发送邮件消息。
演示了文件邮件和HTML格式邮件的发送。接下来
接下来可以添加对邮件附件的支持,这个功能可以留给读者去实现。
相关文章推荐
- 字节序与字节对齐
- 网络编程复习_ Exp2
- java中TCP传输协议
- HttpSessionBindingListener 和HttpSessionListener
- NC - 网络编码的Java实现(1)-GF28基本运算
- [java]HttpSessionListener实现统计在线人数
- 自定义HttpMessageHandler实现HTTP方法的重写
- HttpUrlConnection 的 setDoOutput 与 setDoInput
- Android中的HTTP请求
- Http连网传递参数出现乱码
- Chrome浏览器中的网上应用店如何加载
- libgo协程库:网络性能完爆ASIO异步模型(-O3测试)
- httpclient
- C语言解析pcap文件得到HTTP信息实例
- HTTP错误大全(404,302,200……)
- windows下面配置apache+https(利用SSL)服务器
- BroadcastReceiver获取手机网络状态
- Flex与服务器交互之二(使用HTTPService同服务器交互)
- 【转载】推荐三十款CSS选择器代码 http://www.w3cfuns.com/thread-1361-1-1.html (出处: 前端网(W3Cfuns))
- 使用volley加载网络图片