Advertisement
Cool_Dalek

Simple jakarta.mail wrapper with Scala3 and Cats

Feb 16th, 2023 (edited)
2,786
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 2.97 KB | None | 0 0
  1. import cats.*
  2. import cats.effect.*
  3. import cats.effect.std.*
  4. import cats.syntax.all.*
  5. import io.odin.Logger // can be any logger, log4cats, tofu, etc, odin just for example
  6. import jakarta.mail.*
  7. import jakarta.mail.internet.{InternetAddress, MimeMessage}
  8.  
  9. import scala.concurrent.ExecutionContext
  10.  
  11. trait Mailer[F[_]]:
  12.  
  13.   def send(subject: String, content: String, recipient: String): F[Unit]
  14.  
  15. object Mailer:
  16.  
  17.   case class MailConfig(
  18.                         queueSize: Int,
  19.                         user: String,
  20.                         password: String,
  21.                         sender: String,
  22.                         host: String,
  23.                         port: Int,
  24.                        )
  25.  
  26.   def make[F[_]: Async](blockingEC: ExecutionContext, config: MailConfig, logger: Logger[F]): Resource[F, Mailer[F]] =
  27.     case class Mail(subject: String, content: String, recipient: String)
  28.  
  29.     def send(queue: Queue[F, Mail], sender: InternetAddress, session: Session): F[Unit] =
  30.       queue.take.flatMap { mail =>
  31.         val message = MimeMessage(session)
  32.         message.setFrom(sender)
  33.         message.setRecipients(
  34.           Message.RecipientType.TO,
  35.           InternetAddress.parse(mail.recipient).asInstanceOf[Array[Address]],
  36.         )
  37.         message.setSubject(mail.subject)
  38.         message.setContent(mail.content, "text/html")
  39.         message.saveChanges()
  40.         Async[F].start {
  41.           Async[F].blocking(Transport.send(message))
  42.             .attempt.flatMap {
  43.               case Right(_) =>
  44.                 logger.debug(s"Sent message to ${mail.recipient} with subject ${mail.subject}.")
  45.               case Left(exc) =>
  46.                 logger.error(s"Can't send message to ${mail.recipient} with subject ${mail.subject}.", exc)
  47.             }
  48.         }
  49.       } >> send(queue, sender, session)
  50.     end send
  51.  
  52.     for
  53.       queue <- Resource.eval {
  54.         Queue.bounded[F, Mail](config.queueSize)
  55.       }
  56.       props = System.getProperties
  57.       _ = props.setProperty("mail.smtp.host", config.host)
  58.       _ = props.setProperty("mail.smtp.port", config.port.toString)
  59.       _ = props.setProperty("mail.smtp.auth", true.toString)
  60.       _ = props.setProperty("mail.smtp.starttls.enable", true.toString)
  61.       auth = new Authenticator {
  62.         override protected def getPasswordAuthentication: PasswordAuthentication =
  63.           new PasswordAuthentication (config.user, config.password)
  64.       }
  65.       session = Session.getInstance(props, auth)
  66.       sender = new InternetAddress(config.sender)
  67.       _ <- Async[F].backgroundOn(
  68.         send(queue, sender, session),
  69.         blockingEC,
  70.       )
  71.     yield new Mailer[F] {
  72.  
  73.       override def send(subject: String, content: String, recipient: String): F[Unit] =
  74.         queue.offer(
  75.           Mail(
  76.             subject,
  77.             content,
  78.             email,
  79.           )
  80.         ) *> logger.debug(s"Sending message to ${mail.recipient} with subject ${mail.subject}.")
  81.  
  82.     }
  83.   end make
  84.  
  85. end Mailer
  86.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement