diff --git a/README.adoc b/README.adoc index 4b77dba..19cf5b4 100644 --- a/README.adoc +++ b/README.adoc @@ -35,6 +35,8 @@ play.mailer { } ``` +You can also configure the mailer programmatically, see below. + ## Usage ### Java @@ -61,7 +63,11 @@ public class MyComponent { // sends text, HTML or both... email.setBodyText("A text message"); email.setBodyHtml("

An html message

"); - mailerClient.send(email); + // configures the mailer before sending the email + Map conf = new HashMap<>(); + conf.put("host", "typesafe.org"); + conf.put("port", 1234); + mailerClient.configure(new Configuration(conf)).send(email); } } ``` @@ -91,7 +97,8 @@ class MyComponent @Inject() (mailerClient: MailerClient) { bodyText = Some("A text message"), bodyHtml = Some("

An html message

") ) - mailerClient.send(email) + // configures the mailer before sending the email + mailer.configure(Configuration.from(Map("host" -> "typesafe.org", "port" -> 1234))).send(email) } } ``` diff --git a/sample/app/controllers/ApplicationJava.java b/sample/app/controllers/ApplicationJava.java index be24a5c..ff1be75 100644 --- a/sample/app/controllers/ApplicationJava.java +++ b/sample/app/controllers/ApplicationJava.java @@ -1,6 +1,7 @@ package controllers; import org.apache.commons.mail.EmailAttachment; +import play.Configuration; import play.Play; import play.api.libs.mailer.MailerClient; import play.libs.mailer.Email; @@ -9,6 +10,8 @@ import javax.inject.Inject; import java.io.File; +import java.util.HashMap; +import java.util.Map; public class ApplicationJava extends Controller { @@ -31,5 +34,16 @@ public Result send() { String id = mailer.send(email); return ok("Email " + id + " sent!"); } - + + public Result configureAndSend() { + final Email email = new Email(); + email.setSubject("Simple email"); + email.setFrom("from@email.com"); + email.addTo("to@email.com"); + Map conf = new HashMap<>(); + conf.put("host", "typesafe.org"); + conf.put("port", 1234); + String id = mailer.configure(new Configuration(conf)).send(email); + return ok("Email " + id + " sent!"); + } } diff --git a/sample/app/controllers/ApplicationScala.scala b/sample/app/controllers/ApplicationScala.scala index e21c5ca..e4bc837 100644 --- a/sample/app/controllers/ApplicationScala.scala +++ b/sample/app/controllers/ApplicationScala.scala @@ -4,6 +4,7 @@ import java.io.File import javax.inject.Inject import org.apache.commons.mail.EmailAttachment +import play.api.Configuration import play.api.Play.current import play.api.libs.mailer._ import play.api.mvc.{Action, Controller} @@ -25,4 +26,10 @@ class ApplicationScala @Inject()(mailer: MailerClient) extends Controller { val id = mailer.send(email) Ok(s"Email $id sent!") } + + def configureAndSend = Action { + val email = Email("Simple email", "from@email.com", Seq("to@email.com")) + val id = mailer.configure(Configuration.from(Map("host" -> "typesafe.org", "port" -> 1234))).send(email) + Ok(s"Email $id sent!") + } } diff --git a/sample/build.sbt b/sample/build.sbt index 172870d..63153ee 100644 --- a/sample/build.sbt +++ b/sample/build.sbt @@ -10,7 +10,7 @@ scalaVersion := "2.11.6" resolvers += "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases" libraryDependencies ++= Seq( - "com.typesafe.play" %% "play-mailer" % "3.0.1-SNAPSHOT" + "com.typesafe.play" %% "play-mailer" % "3.0.2-SNAPSHOT" ) routesGenerator := InjectedRoutesGenerator diff --git a/sample/conf/routes b/sample/conf/routes index 912be50..4641222 100644 --- a/sample/conf/routes +++ b/sample/conf/routes @@ -2,5 +2,8 @@ # This file defines all application routes (Higher priority routes first) # ~~~~ -GET /send/java controllers.ApplicationJava.send() -GET /send/scala controllers.ApplicationScala.send() +GET /send/java controllers.ApplicationJava.send() +GET /send/scala controllers.ApplicationScala.send() + +GET /configureAndSend/java controllers.ApplicationJava.configureAndSend() +GET /configureAndSend/scala controllers.ApplicationScala.configureAndSend() diff --git a/src/main/java/play/libs/mailer/MailerClient.java b/src/main/java/play/libs/mailer/MailerClient.java index 4a88625..1cd6483 100644 --- a/src/main/java/play/libs/mailer/MailerClient.java +++ b/src/main/java/play/libs/mailer/MailerClient.java @@ -1,5 +1,7 @@ package play.libs.mailer; +import play.Configuration; + /** * A mailer client. */ @@ -12,4 +14,12 @@ public interface MailerClient { * @return The message id. */ String send(Email email); + + /** + * Configure the underlying instance of mailer + * + * @param configuration The configuration + * @return The mailer client + */ + MailerClient configure(Configuration configuration); } diff --git a/src/main/scala/play/api/libs/mailer/MailerPlugin.scala b/src/main/scala/play/api/libs/mailer/MailerPlugin.scala index 64559ce..18aa252 100644 --- a/src/main/scala/play/api/libs/mailer/MailerPlugin.scala +++ b/src/main/scala/play/api/libs/mailer/MailerPlugin.scala @@ -8,6 +8,7 @@ import org.apache.commons.mail._ import play.api.inject._ import play.api.{Configuration, Environment, Logger, PlayConfig} import play.libs.mailer.{Email => JEmail, MailerClient => JMailerClient} +import play.{Configuration => JConfiguration} import scala.collection.JavaConverters._ @@ -38,12 +39,24 @@ trait MailerClient extends JMailerClient { */ def send(data: Email): String + /** + * Configure the underlying instance of mailer. + * + * @param configuration configuration + * @return the mailer client + */ + def configure(configuration: Configuration): MailerClient + + override def configure(configuration: JConfiguration): JMailerClient = { + configure(Configuration(configuration.underlying())) + } + override def send(data: JEmail): String = { val email = convert(data) send(email) } - protected def convert(data: play.libs.mailer.Email): Email = { + protected def convert(data: JEmail): Email = { val attachments = data.getAttachments.asScala.map { case attachment => if (Option(attachment.getFile).isDefined) { @@ -79,14 +92,14 @@ trait MailerClient extends JMailerClient { class CommonsMailer @Inject()(configuration: Configuration) extends MailerClient { - private val mailerConfig = PlayConfig(configuration).getDeprecatedWithFallback("play.mailer", "smtp") - private lazy val mock = mailerConfig.get[Boolean]("mock") + private val defaultConfig = PlayConfig(configuration).getDeprecatedWithFallback("play.mailer", "smtp") + private lazy val mock = defaultConfig.get[Boolean]("mock") private lazy val instance = { if (mock) { new MockMailer() } else { - new SMTPMailer(SMTPConfiguration(mailerConfig)) { + new SMTPMailer(defaultConfig) { override def send(email: MultiPartEmail): String = email.send() override def createMultiPartEmail(): MultiPartEmail = new MultiPartEmail() override def createHtmlEmail(): HtmlEmail = new HtmlEmail() @@ -94,10 +107,16 @@ class CommonsMailer @Inject()(configuration: Configuration) extends MailerClient } } - override def send(data: Email): String = instance.send(data) + override def send(data: Email): String = { + instance.send(data) + } + + override def configure(configuration: Configuration) = { + instance.configure(configuration) + } } -abstract class SMTPMailer(config: SMTPConfiguration) extends MailerClient { +abstract class SMTPMailer(defaultConfig: PlayConfig, var config: Option[SMTPConfiguration] = None) extends MailerClient { def send(email: MultiPartEmail): String @@ -107,7 +126,13 @@ abstract class SMTPMailer(config: SMTPConfiguration) extends MailerClient { override def send(data: Email): String = send(createEmail(data)) + override def configure(configuration: Configuration) = { + config = Some(SMTPConfiguration(PlayConfig(Configuration.reference.getConfig("play.mailer").get ++ configuration))) + this + } + def createEmail(data: Email): MultiPartEmail = { + val conf = config.getOrElse(SMTPConfiguration(defaultConfig)) val email = createEmail(data.bodyText, data.bodyHtml, data.charset.getOrElse("utf-8")) email.setSubject(data.subject) setAddress(data.from) { (address, name) => email.setFrom(address, name) } @@ -119,8 +144,8 @@ abstract class SMTPMailer(config: SMTPConfiguration) extends MailerClient { data.headers.foreach { header => email.addHeader(header._1, header._2) } - config.timeout.foreach(email.setSocketTimeout) - config.connectionTimeout.foreach(email.setSocketConnectionTimeout) + conf.timeout.foreach(email.setSocketTimeout) + conf.connectionTimeout.foreach(email.setSocketConnectionTimeout) data.attachments.foreach { case attachmentData: AttachmentData => val description = attachmentData.description.getOrElse(attachmentData.name) @@ -137,16 +162,16 @@ abstract class SMTPMailer(config: SMTPConfiguration) extends MailerClient { emailAttachment.setDisposition(disposition) email.attach(emailAttachment) } - email.setHostName(config.host) - email.setSmtpPort(config.port) - email.setSSLOnConnect(config.ssl) - if (config.ssl) { - email.setSslSmtpPort(config.port.toString) + email.setHostName(conf.host) + email.setSmtpPort(conf.port) + email.setSSLOnConnect(conf.ssl) + if (conf.ssl) { + email.setSslSmtpPort(conf.port.toString) } - email.setStartTLSEnabled(config.tls) - for (u <- config.user; p <- config.password) yield email.setAuthenticator(new DefaultAuthenticator(u, p)) - if (config.debugMode && Logger.isDebugEnabled) { - email.setDebug(config.debugMode) + email.setStartTLSEnabled(conf.tls) + for (u <- conf.user; p <- conf.password) yield email.setAuthenticator(new DefaultAuthenticator(u, p)) + if (conf.debugMode && Logger.isDebugEnabled) { + email.setDebug(conf.debugMode) email.getMailSession.setDebugOut(new PrintStream(new FilterOutputStream(null) { override def write(b: Array[Byte]) { Logger.debug(new String(b)) @@ -222,6 +247,8 @@ class MockMailer @Inject() extends MailerClient { email.headers.foreach(header => Logger.info(s"header: $header")) "" } + + override def configure(configuration: Configuration) = this } sealed trait Attachment @@ -263,7 +290,7 @@ case class SMTPConfiguration(host: String, object SMTPConfiguration { def apply(config: PlayConfig) = new SMTPConfiguration( - config.getOptional[String]("host").getOrElse(throw new RuntimeException("play.mailer.host needs to be set in application.conf in order to use this plugin (or set play.mailer.mock to true)")), + config.getOptional[String]("host").getOrElse(throw new RuntimeException("host needs to be set in order to use this plugin (or set play.mailer.mock to true in application.conf)")), config.get[Int]("port"), config.get[Boolean]("ssl"), config.get[Boolean]("tls"), @@ -273,4 +300,4 @@ object SMTPConfiguration { config.getOptional[Int]("timeout"), config.getOptional[Int]("connectiontimeout") ) -} +} \ No newline at end of file diff --git a/src/test/scala/play/api/libs/mailer/MailerPluginSpec.scala b/src/test/scala/play/api/libs/mailer/MailerPluginSpec.scala index b97cd87..f4ae587 100644 --- a/src/test/scala/play/api/libs/mailer/MailerPluginSpec.scala +++ b/src/test/scala/play/api/libs/mailer/MailerPluginSpec.scala @@ -5,6 +5,7 @@ import javax.mail.Part import org.apache.commons.mail.{EmailConstants, HtmlEmail, MultiPartEmail} import org.specs2.mutable._ +import play.api.{PlayConfig, Configuration} import play.api.test._ class MailerPluginSpec extends Specification { @@ -12,6 +13,7 @@ class MailerPluginSpec extends Specification { object SimpleMailerClient extends MailerClient { override def send(data: Email): String = "" override def convert(data: play.libs.mailer.Email) = super.convert(data) + override def configure(configuration: Configuration): MailerClient = this } class MockMultiPartEmail extends MultiPartEmail { override def getPrimaryBodyPart = super.getPrimaryBodyPart @@ -26,7 +28,7 @@ class MailerPluginSpec extends Specification { object MockSMTPMailer extends MockSMTPMailerWithTimeouts(None, None) class MockSMTPMailerWithTimeouts(smtpTimeout: Option[Int], smtpConnectionTimeout: Option[Int]) - extends SMTPMailer(SMTPConfiguration("typesafe.org", 1234, ssl = true, tls = false, Some("user"), Some("password"), debugMode = false, smtpTimeout, smtpConnectionTimeout)) { + extends SMTPMailer(PlayConfig(Configuration.empty), Some(SMTPConfiguration("typesafe.org", 1234, ssl = true, tls = false, Some("user"), Some("password"), debugMode = false, smtpTimeout, smtpConnectionTimeout))) { override def send(email: MultiPartEmail) = "" override def createMultiPartEmail(): MultiPartEmail = new MockMultiPartEmail override def createHtmlEmail(): HtmlEmail = new MockHtmlEmail @@ -47,6 +49,27 @@ class MailerPluginSpec extends Specification { email.getMailSession.getProperty("mail.debug") mustEqual "false" } + "reconfigure SMTP" in { + val mailer = MockSMTPMailer + mailer.configure(Configuration.from(Map( + "host" -> "playframework.com", + "port" -> 5678, + "ssl" -> false, + "tls" -> true + ))) + val email = mailer.createEmail(Email( + subject = "Subject", + from = "James Roper " + )) + email.getSmtpPort mustEqual "5678" + // Default value + email.getSslSmtpPort mustEqual "465" + email.getMailSession.getProperty("mail.smtp.auth") must beNull + email.getMailSession.getProperty("mail.smtp.host") mustEqual "playframework.com" + email.getMailSession.getProperty("mail.smtp.starttls.enable") mustEqual "true" + email.getMailSession.getProperty("mail.debug") mustEqual "false" + } + "configure the SMTP timeouts if configured" in { val mailer = new MockSMTPMailerWithTimeouts(Some(10), Some(99)) val email = mailer.createEmail(Email(