eikek / emil

Emil is a library for dealing with E-Mail in Scala.

Version Matrix

Emil - Email without a

Build Status Scaladex Scala Steward badge

[\/] Emil is a library for working with E-Mail in Scala. The api builds on Cats and FS2. It comes with a backend implementation that is based on the well known Java Mail library. As such it is just another wrapper library, but also a bit different:

  • Extensible DSL for creating mails in code.
  • Conveniently send mails via SMTP.
  • Search mail boxes via IMAP.
  • The data structures model a simplified E-Mail structure. Instead of adhering to the recursive structure of a mime message, a mail here is flat, consisting of a header, a body (text, html or both) and a list of attachments.
  • The data structures and api are in a separate module, that doesn't depend on a concrete implementation library, like Java Mail. An implementation based on fs2-mail or even EWS can be created without affecting the user code of this library.

Write your e-mail related code once and then decide how to execute.

Examples

Send a mail (returning its messageID):

import cats.effect._
import cats.data.NonEmptyList
import emil._, emil.builder._
import emil.javamail._

implicit val CS = IO.contextShift(scala.concurrent.ExecutionContext.global)
val blocker = Blocker.liftExecutionContext(scala.concurrent.ExecutionContext.global)

val mail: Mail[IO] = MailBuilder.build(
  From("me@test.com"),
  To("test@test.com"),
  Subject("Hello!"),
  CustomHeader(Header("User-Agent", "my-email-client")),
  TextBody("Hello!\n\nThis is a mail."),
  HtmlBody("<h1>Hello!</h1>\n<p>This <b>is</b> a mail.</p>"),
  AttachUrl[IO](getClass.getResource("/files/Test.pdf"), blocker).
    withFilename("test.pdf").
    withMimeType(MimeType.pdf)
)

val myemil = JavaMailEmil[IO](blocker)
val smtpConf = MailConfig("smtp://devmail:25", "dev", "dev", SSLType.NoEncryption)

val sendIO: IO[NonEmptyList[String]] = myemil(smtpConf).send(mail)

Searching for mails:

import java.time._
import cats.effect._
import emil._
import emil.SearchQuery._
import emil.javamail._

implicit val CS = IO.contextShift(scala.concurrent.ExecutionContext.global)
val blocker = Blocker.liftExecutionContext(scala.concurrent.ExecutionContext.global)

val myemil = JavaMailEmil[IO](blocker)
val imapConf = MailConfig("imap://devmail:143", "dev", "dev", SSLType.NoEncryption)

def searchInbox[C](a: Access[IO, C], q: SearchQuery): MailOp[IO, C, SearchResult[MailHeader]] =
  for {
    inbox  <- a.getInbox
    mails  <- a.search(inbox, 20)(q)
  } yield mails


val q = (ReceivedDate >= Instant.now.minusSeconds(60)) && (Subject =*= "test")
val searchIO: IO[SearchResult[MailHeader]] = myemil(imapConf).run(searchInbox(myemil.access, q))

Documentation

More information can be found here.