Mocking Mail API in Scala

Knoldus Inc.
Knoldus - Technical Insights
3 min readMay 16, 2016

Few days ago I was working on a Mailing API of my project and used javax-mail API but encountered the problem of how to write unit test cases for that without actually mocking the mail. I searched for it but was unable to find a proper documentation about mocking a mailing service. I tried few methods but some were confusing and some were really complex. Then I found Mock-JavaMail dependency which is quite easy to handle. Just add it and we are done.

I am using SBT project therefore using SBT dependency but you can find other relevant dependency on maven repository that will suit your project.

Let’s take an example:

First we add the required dependencies in our project.

[code language=”scala”]libraryDependencies ++= Seq(
“javax.mail” % “mail” % “1.4”,
“org.jvnet.mock-javamail” % “mock-javamail” % “1.9” % “test”,
“org.scalatest” % “scalatest_2.11” % “3.0.0-M15”,
“com.typesafe” % “config” % “1.3.0”,
“ch.qos.logback” % “logback-classic” % “1.1.7”
)[/code]

Then we create the necessary variables in our class.

[code language=”scala”]final val EMPTY_STRING = “”
val logger: Logger = LoggerFactory.getLogger(this.getClass())
val conf = ConfigFactory.systemEnvironment()
val senderEmail = try {
conf.getString(“email”)
} catch {
case ex: Exception =>
logger.error(“Email key not set.\nPlease add email variable using -> export email=your_email@domain.com”)
EMPTY_STRING
}

val password = try {
conf.getString(“password”)
} catch {
case ex: Exception =>
logger.error(“Password key not set.\nPlease add password variable using -> export password=your_password”)
EMPTY_STRING
}
val hostName = “smtp.gmail.com”

val port = “587”

val properties = new Properties
properties.put(“mail.smtp.port”, port)
properties.setProperty(“mail.transport.protocol”, “smtp”)
properties.setProperty(“mail.smtp.starttls.enable”, “true”)
properties.setProperty(“mail.host”, hostName)
properties.setProperty(“mail.user”, senderEmail)
properties.setProperty(“mail.password”, password)
properties.setProperty(“mail.smtp.auth”, “true”)

val session = Session.getDefaultInstance(properties)
[/code]

Here I am taking email and password from system environment variables, to use them you need to set them as following:

export email=your_email@domain.com

export password=your_password

Then we will use above variable in method mentioned below. I’ve written two methods, one for sending mail to multiple emails and one for a single email id and I’ve used method overloading functionality for that.

[code language=”scala”]def sendMail(recipient: List[String], subject: String, content: String): Option[Int] = {
try {
val message = new MimeMessage(session)
message.setFrom(new InternetAddress(senderEmail))
val recipientAddress: Array[Address] = (recipient map { recipient => new InternetAddress(recipient) }).toArray
message.addRecipients(Message.RecipientType.TO, recipientAddress)
message.setSubject(subject)
message.setHeader(“Content-Type”, “text/plain;”)
message.setContent(content, “text/html”)
val transport = session.getTransport(“smtp”)
transport.connect(hostName, senderEmail, password)
transport.sendMessage(message, message.getAllRecipients)
logger.info(“Email Sent!!”)
Some(recipient.size)
}
catch {
case exception: Exception =>
logger.error(“Mail delivery failed. “ + exception)
None
}
}

def sendMail(recipient: String, subject: String, content: String): Option[Int] = {
try {
val message = new MimeMessage(session)
message.setFrom(new InternetAddress(senderEmail))
message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient))
message.setSubject(subject)
message.setHeader(“Content-Type”, “text/plain;”)
message.setContent(content, “text/html”)
val transport = session.getTransport(“smtp”)
transport.connect(hostName, senderEmail, password)
transport.sendMessage(message, message.getAllRecipients)
logger.info(“Email Sent!!”)
Some(recipient.length)
}
catch {
case exception: Exception =>
logger.error(“Mail delivery failed. “ + exception)
None
}
}[/code]

Now let’s move to the real motive of this blog which is mocking mail. I’ve used ScalaTest for testing my class. Now all you have to do is to write unit test cases and Mock-JavaMail will redirect all mails to in-memory .

Note: Mock-JavaMail will redirect all mails to in-memory so don’t forget to add scope as test otherwise you will not be able to send mail from your production code.

“groupId” % “artifactId” % “version” % “scope”

Unit Test Code:

[code language=”scala”]package com.knoldus.email

import org.scalatest.FunSuite

class MailerAPITest extends FunSuite {

val emailAgent = new MailerAPI
val recipientList = List(“prabhatkashyap33@gmail.com”)
val subject = “This is my Subject”
val message = “This is my Message”

val recipient = “prabhatkashyap33@gmail.com”

test(“Send Email to one address”){
val result = emailAgent.sendMail(recipient, subject, message)
assert(result.isDefined)
}

test(“Send Email to multiple address”){
val result = emailAgent.sendMail(recipientList, subject, message)
assert(result.isDefined)
}

}[/code]

See complete source code on GitHub

--

--

Knoldus Inc.
Knoldus - Technical Insights

Group of smart Engineers with a Product mindset who partner with your business to drive competitive advantage | www.knoldus.com