All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.clapper.avsl.handler.email.scala Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package org.clapper.avsl.handler

import org.clapper.avsl.{LogLevel, LogMessage}
import org.clapper.avsl.formatter.Formatter
import org.clapper.avsl.config.ConfiguredArguments
import org.clapper.avsl.AVSLConfigException

import java.util.{Date, Properties};

import javax.activation.{DataHandler, DataSource, FileTypeMap}
import javax.mail.{Address, Message, MessagingException, Session, Transport}
import javax.mail.internet.{InternetAddress, MimeBodyPart, MimeMessage,
                            MimeMultipart}

import scala.util.Try

/**
  * Handler that emails each message, separate, to a set of recipients.
  * `args` must contain:
  *
  * - `sender`: Email address of sender.
  * - `recipients`: comma-separated list of email addresses to receive log
  *    messages.
  *
  * `args` may also contain:
  *
  * - `smtp.server`: hostname of SMTP server. Defaults to "localhost".
  * - `smtp.port`: integer port on which SMTP server accepts messages. Defaults
  *   to 25.
  * - `subject`: Subject of message. Subject may contain "%l" for the level
  *   name. Defaults to: %l message
  */
class EmailHandler(args: ConfiguredArguments,
                   val formatter: Formatter,
                   val level: LogLevel)
extends Handler {
  // Pull the argument values.

  val sender = args.get("sender").
                    map { new InternetAddress(_) }.
                    getOrElse {
    throw new AVSLConfigException("Missing 'sender' for EmailHandler.")
  }

  val recipients = args.get("recipients").map {
    InternetAddress.parse(_, true).map { _.asInstanceOf[Address] }
  }.
  getOrElse {
    throw new AVSLConfigException("No recipients specified " +
                                  "for email handler.")
  }

  val smtpServer = args.getOrElse("smtp.server", "localhost")

  val smtpPort = args.get("smtp.port").map { sPort =>
    Try {
      sPort.toInt
    }.
    recover { case ex: NumberFormatException =>
      throw new AVSLConfigException("Bad SMTP port: " + sPort)
    }.
    get
  }

  val subject = args.getOrElse("subject", "%l message")

  // Initialize the JavaMail properties.

  private lazy val props = new Properties
  props.put("mail.smtp.host", smtpServer)
  props.put("mail.smtp.allow8bitmime", "true")

  // Prepare the JavaMail session and transport.

  private lazy val session = Session.getDefaultInstance(props, null)
  private lazy val transport = session.getTransport("smtp")

  // ----------------------------------------------------------------------
  // Classes
  // ----------------------------------------------------------------------

  /** A Java Activation Framework (JAF) DataSource that reads from a
    * string. Why such a thing isn't included in the JAF API escapes my
    * meager cognitive abilities.
    */
  private class StringDataSource(s: String) extends DataSource {

    import java.io.{InputStream, OutputStream, IOException,
                    ByteArrayInputStream}

    val contentType = "text/plain"

    def getInputStream(): InputStream =
      new ByteArrayInputStream(s.getBytes)

    def getOutputStream(): OutputStream =
      throw new IOException("OutputStream not supported for string")

    def getContentType() = contentType

    def getName() = "body"
  }

  // ----------------------------------------------------------------------
  // Methods
  // ----------------------------------------------------------------------

  def log(message: String, logMessage: LogMessage) = {
    // Create a new message. (Isn't this fun?)

    val mailMessage = new MimeMessage(session)
    val body = new MimeMultipart

    val bodyPart = new MimeBodyPart
    bodyPart.setDataHandler(new DataHandler(new StringDataSource(message)))

    body.addBodyPart(bodyPart)

    mailMessage.setSender(sender)
    mailMessage.setFrom(sender)
    mailMessage.setRecipients(Message.RecipientType.TO, recipients)
    mailMessage.setSubject(subject.replaceAll("%l", logMessage.level.label))
    mailMessage.setContent(body)
    mailMessage.addHeaderLine("X-Mailer: " + this.getClass.getName)
    mailMessage.setSentDate(new Date)

    // Connect to the SMTP server and send the message.

    transport.connect
    Transport.send(mailMessage)
    transport.close
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy