I'm planning to build a service using Scala and Akka that is going to depend on e-mail heavily. In fact, most of the communication with my service will be done by sending letters to it and getting a replies. I guess this means I need a reliable email server and ways to communicate with it from Scala.
Question is, what are the best practices for doing this? Which email server should I choose and what Scala solutions are there to accomplish this task?
Usually JavaMail API is used. In your project you can wrap it in your own Scala library or use existing one. Here is an example of using existing Mailer API in Lift framework:
package code
package config
import javax.mail.{Authenticator, PasswordAuthentication}
import javax.mail.internet.MimeMessage
import net.liftweb._
import common._
import util._
/*
* A Mailer config object that uses Props and auto configures for gmail
* if detected.
*/
object SmtpMailer extends Loggable {
def init(): Unit = {
var isAuth = Props.get("mail.smtp.auth", "false").toBoolean
Mailer.customProperties = Props.get("mail.smtp.host", "localhost") match {
case "smtp.gmail.com" => // auto configure for gmail
isAuth = true
Map(
"mail.smtp.host" -> "smtp.gmail.com",
"mail.smtp.port" -> "587",
"mail.smtp.auth" -> "true",
"mail.smtp.starttls.enable" -> "true"
)
case h => Map(
"mail.smtp.host" -> h,
"mail.smtp.port" -> Props.get("mail.smtp.port", "25"),
"mail.smtp.auth" -> isAuth.toString
)
}
//Mailer.devModeSend.default.set((m : MimeMessage) => logger.info("Sending Mime Message: "+m))
if (isAuth) {
(Props.get("mail.smtp.user"), Props.get("mail.smtp.pass")) match {
case (Full(username), Full(password)) =>
logger.info("Smtp user: %s".format(username))
logger.info("Smtp password length: %s".format(password.length))
Mailer.authenticator = Full(new Authenticator() {
override def getPasswordAuthentication = new
PasswordAuthentication(username, password)
})
logger.info("SmtpMailer inited")
case _ => logger.error("Username/password not supplied for Mailer.")
}
}
}
}
Many web frameworks would implement conveniece methods for you to deal with mime types, attachments, etc.
Needless to say that sending email is never 100% reliable. It's more like fire and forget operation. There is no confirmation or error propagation in mail protocols by default which is usually accepted as normal.
If you use SMTP mail sender you can connect it to any mail server whether it's an external one like gmail, or locally installed postfix.
You can try courier which is a Scala layer on top of Java Mail that gives more fluent API. Unfortunately, at the moment there are no non-blocking solution for email sending on the JVM (correct me if I'm wrong).
Related
I want to implement an client app that first send an request to server then wait for its reply(similar to http)
My client process may be
val topic = async.topic[ByteVector]
val client = topic.subscribe
Here is the api
trait Client {
val incoming = tcp.connect(...)(client)
val reqBus = topic.pubsh()
def ask(req: ByteVector): Task[Throwable \/ ByteVector] = {
(tcp.writes(req).flatMap(_ => tcp.reads(1024))).to(reqBus)
???
}
}
Then, how to implement the remain part of ask ?
Usually, the implementation is done with publishing the message via sink and then awaiting some sort of reply on some source, like your topic.
Actually we have a lot of idioms of this in our code :
def reqRply[I,O,O2](src:Process[Task,I],sink:Sink[Task,I],reply:Process[Task,O])(pf: PartialFunction[O,O2]):Process[Task,O2] = {
merge.mergeN(Process(reply, (src to sink).drain)).collectFirst(pf)
}
Essentially this first hooks to reply stream to await any resulting O confirming our request sent. Then we publish message I and consult pf for any incoming O to be eventually translated to O2 and then terminate.
I am making a Play web-socket app. When a client connects, I want to send a welcome message.
The code I use is below:
package controllers
import play.api._
import play.api.mvc._
import play.api.libs.iteratee.Concurrent
import play.api.libs.iteratee.Iteratee
import play.api.libs.concurrent.Execution.Implicits.defaultContext
object Test extends Controller {
def index = WebSocket.using[String] { _ =>
val (out,channel) = Concurrent.broadcast[String]
channel.push("Welcome to MyWebSocket")
val in = Iteratee.foreach[String] {
_ match {
case any => channel.push(any)
}
}
(in, out)
}
}
The code works fine when a client sends a message and the server has to respond to it. However, the initial welcome message Welcome to MyWebSocket is not sent. How can I fix this code?
[EDIT]
I kind of figured out the problem, but not a solution yet. The problem probably occurs because the websocket is not yet initialized when the welcome message is being pushed. I modified the code and replaced:
channel.push("Welcome to MyWebSocket")
with
val a = scala.concurrent.Future {
Thread.sleep(1000)
channel.push("Welcome to MyWebSocket")
}
After this I get the expected results (welcome message received by client). I think using the above approach (Thread.sleep and Future) is not the right way to solve this problem, so other solutions are welcome. It could also be a problem with the client side code which takes a while to initialize the socket. I used Firefox and echo web-socket test for the client.
You can use WebSocket.acceptWithActor helper method (have a look at this) and in actor body make something like
out ! "Welcome to MyWebSocket"
It works nicely.
I am trying to create a jetty consumer. I am able to get it successfully running using the endpoint uri:
jetty:http://0.0.0.0:8080
However, when I modify the endpoint uri for https:
jetty:https://0.0.0.0:8443
The page times out trying to load. This seems odd because the camel documentation states it should function right out of the box.
I have since loaded a signed SSL into java's default keystore, with my attempted implementation to load it below:http://camel.apache.org/jetty.html
I have a basic Jetty instance using the akka-camel library with akka and scala. ex:
class RestActor extends Actor with Consumer {
val ksp: KeyStoreParameters = new KeyStoreParameters();
ksp.setPassword("...");
val kmp: KeyManagersParameters = new KeyManagersParameters();
kmp.setKeyStore(ksp);
val scp: SSLContextParameters = new SSLContextParameters();
scp.setKeyManagers(kmp);
val jettyComponent: JettyHttpComponent = CamelExtension(context.system).context.getComponent("jetty", classOf[JettyHttpComponent])
jettyComponent.setSslContextParameters(scp);
def endpointUri = "jetty:https://0.0.0.0:8443/"
def receive = {
case msg: CamelMessage => {
...
}
...
}
...
}
This resulted in some progress, because the page does not timeout anymore, but instead gives a "The connection was interrupted" error. I am not sure where to go from here because camel is not throwing any Exceptions, but rather failing silently somewhere (apparently).
Does anybody know what would cause this behavior?
When using java's "keytool" I did not specify an output file. It didn't throw back an error, so it probably went somewhere. I created a new keystore and explicitly imported my crt into the keyfile. I then explicitly added the filepath to that keystore I created, and everything works now!
If I had to speculate, it is possible things failed silently because I was adding the certs to jetty's general bank of certs to use if eligible, instead of explicitly binding it as the SSL for the endpoint.
class RestActor extends Actor with Consumer {
val ksp: KeyStoreParameters = new KeyStoreParameters();
ksp.setResource("/path/to/keystore");
ksp.setPassword("...");
val kmp: KeyManagersParameters = new KeyManagersParameters();
kmp.setKeyStore(ksp);
val scp: SSLContextParameters = new SSLContextParameters();
scp.setKeyManagers(kmp);
val jettyComponent: JettyHttpComponent = CamelExtension(context.system).context.getComponent("jetty", classOf[JettyHttpComponent])
jettyComponent.setSslContextParameters(scp);
def endpointUri = "jetty:https://0.0.0.0:8443/"
def receive = {
case msg: CamelMessage => {
...
}
...
}
...
}
Hopefully somebody in the future can find use for this code as a template in implementing Jetty over SSL with akka-camel (surprisingly no examples seem to exist)
I want to forbid the full access to the Solr core from outside, and let it be used only for querying. Thus I am launching secondary server w/ connector instance inside Jetty servlet container (besides, the main webapp) on the port, that is not accessible from the WWW.
When there is incoming HTTP request to the liftweb application, I hook with RestHelper:
object Dispatcher extends RestHelper {
serve {
case List("api", a # _*) JsonGet _ => JString("API is not implemented yet. rest: " + a)
}
}
Targeting my browser to http://localhost/api/solr/select?q=region I get a response "API is not implemented yet. rest: List(solr, select)", so it seems to work. Now I want to do a connection on internal port (where Solr resides) in order to pass the query using the post-api part of the URL (i.e. http://localhost:8080/solr/select?q=region). I am catching the trailing REST-part of the URL (by means of a # _*), but how can I access URL parameters? It would be ideal to pass a raw string (after api path element) to the Solr instance, just to prevent redundant parse/build steps. So applies to the Solr's response: I would like to avoid parsing building JsonResponse.
This seems to be a good example on doing some HTTP-redirection, but then I would have to open the hidden Solr's port, as far as I can understand.
What is the most effective way to cope with this task?
EDIT:
Well, I missed that after JsonGet comes Req value, which has all the needed info. But is there still a way to avoid unwanted parsing/composing URL to hidden port and JSON-response?
SOLUTION:
This is what I've got consdering Dave's suggestion:
import net.liftweb.common.Full
import net.liftweb.http.{JsonResponse, InMemoryResponse}
import net.liftweb.http.provider.HTTPRequest
import net.liftweb.http.rest.RestHelper
import dispatch.{Http, url}
object ApiDispatcher extends RestHelper {
private val SOLR_PORT = 8080
serve { "api" :: Nil prefix {
case JsonGet(path # List("solr", "select"), r) =>
val u = localApiUrl(SOLR_PORT, path, r.request)
Http(url(u) >> { is =>
val bytes = Stream.continually(is.read).takeWhile(-1 !=).map(_.toByte).toArray
val headers = ("Content-Length", bytes.length.toString) ::
("Content-Type", "application/json; charset=utf-8") :: JsonResponse.headers
Full(InMemoryResponse(bytes, headers, JsonResponse.cookies, 200))
})
}}
private def localApiUrl(port: Int, path: List[String], r: HTTPRequest) =
"%s://localhost:%d/%s%s".format(r.scheme, port, path mkString "/", r.queryString.map("?" + _).openOr(""))
}
I'm not sure that I understand your question, but if you want to return the JSON you receive from solr without parsing it you could use a net.liftweb.http.InMemoryResponse that contains a byte[] representation of the JSON.
I am writing a simple chat server, and I want to keep it as simple as possible. My server listed below only receives connections and stores them in the clients set. Incoming messages are then broadcasted to all clients on that Server. The server works with no problem, but on the client side, the RemoteActor stops my program from termination. Is there a way to remove the Actor on my client without terminating the Actor on the Server?
I don't want to use a "one actor per client" model yet.
import actors.{Actor,OutputChannel}
import actors.remote.RemoteActor
object Server extends Actor{
val clients = new collection.mutable.HashSet[OutputChannel[Any]]
def act{
loop{
react{
case 'Connect =>
clients += sender
case 'Disconnect =>
clients -= sender
case message:String =>
for(client <- clients)
client ! message
}
}
}
def main(args:Array[String]){
start
RemoteActor.alive(9999)
RemoteActor.register('server,this)
}
}
my client would then look like this
val server = RemoteActor.select(Node("localhost",9999),'server)
server.send('Connect,messageHandler) //answers will be redirected to the messageHandler
/*do something until quit*/
server ! 'Disconnect
I would suggest placing the client side code into an actor itself - ie not calling alive/register in the main thread
(implied by http://www.scala-lang.org/api/current/scala/actors/remote/RemoteActor$.html)
something like
//body of your main:
val client = actor {
alive(..)
register(...)
loop {
receive {
case 'QUIT => exit()
}
}
}
client.start
//then to quit:
client ! 'QUIT
Or similar (sorry I am not using 2.8 so might have messed something up - feel free to edit if you make it actually work for you !).