|
Lift Framework example source code file (Mailer.scala)
The Lift Framework Mailer.scala source code/* * Copyright 2006-2011 WorldWide Conferencing, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.liftweb package util import javax.mail._ import javax.mail.internet._ import javax.naming.{Context, InitialContext} import java.util.Properties import common._ import actor._ import xml.{Text, Elem, Node, NodeSeq} /** * Utilities for sending email. */ object Mailer extends Mailer /** * This trait implmenets the mail sending. You can create subclasses of this class/trait and * implement your own mailer functionality */ trait Mailer extends SimpleInjector { private val logger = Logger(classOf[Mailer]) sealed abstract class MailTypes /** * Add message headers to outgoing messages */ final case class MessageHeader(name: String, value: String) extends MailTypes abstract class MailBodyType extends MailTypes final case class PlusImageHolder(name: String, mimeType: String, bytes: Array[Byte]) /** * Represents a text/plain mail body. The given text will * be encoded as UTF-8 when sent. */ final case class PlainMailBodyType(text: String) extends MailBodyType /** * Represents a text/plain mail body that is encoded with the * specified charset */ final case class PlainPlusBodyType(text: String, charset: String) extends MailBodyType final case class XHTMLMailBodyType(text: NodeSeq) extends MailBodyType final case class XHTMLPlusImages(text: NodeSeq, items: PlusImageHolder*) extends MailBodyType sealed abstract class RoutingType extends MailTypes sealed abstract class AddressType extends RoutingType { def address: String def name: Box[String] } final case class From(address: String, name: Box[String] = Empty) extends AddressType final case class To(address: String, name: Box[String] = Empty) extends AddressType final case class CC(address: String, name: Box[String] = Empty) extends AddressType final case class Subject(subject: String) extends RoutingType final case class BCC(address: String, name: Box[String] = Empty) extends AddressType final case class ReplyTo(address: String, name: Box[String] = Empty) extends AddressType implicit def xmlToMailBodyType(html: NodeSeq): MailBodyType = XHTMLMailBodyType(html) final case class MessageInfo(from: From, subject: Subject, info: List[MailTypes]) implicit def addressToAddress(in: AddressType): Address = { val ret = new InternetAddress(in.address) in.name.foreach{n => ret.setPersonal(n)} ret } implicit def adListToAdArray(in: List[AddressType]): Array[Address] = in.map(addressToAddress).toArray /** * Passwords cannot be accessed via System.getProperty. Instead, we * provide a means of explicitlysetting the authenticator. */ //def authenticator = authenticatorFunc var authenticator: Box[Authenticator] = Empty /** * Use the mailer resource in your container by specifying the JNDI name */ var jndiName: Box[String] = Empty /** * Custom properties for the JNDI session */ var customProperties: Map[String, String] = Map() lazy val jndiSession: Box[Session] = for{ name <- jndiName contextObj <- Helpers.tryo(new InitialContext().lookup("java:comp/env")) context <- Box.asA[Context](contextObj) sessionObj <- Helpers.tryo(context.lookup(name)) session <- Box.asA[Session](sessionObj) } yield session lazy val properties: Properties = { val p = System.getProperties.clone.asInstanceOf[Properties] customProperties.foreach {case (name, value) => p.put(name, value)} // allow the properties file to set/override system properties Props.props.foreach { case (name, value) => p.setProperty(name, value) } p } /** * The host that should be used to send mail. */ def host = hostFunc() /** * To change the way the host is calculated, set this to the function that calcualtes the host name. * By default: System.getProperty("mail.smtp.host") */ var hostFunc: () => String = _host _ private def _host = properties.getProperty("mail.smtp.host") match { case null => "localhost" case s => s } def buildProps: Properties = { val p = properties.clone.asInstanceOf[Properties] p.getProperty("mail.smtp.host") match { case null => p.put("mail.smtp.host", host) case _ => } p } /** * Set the mail.charset property to something other than UTF-8 for non-UTF-8 * mail. */ lazy val charSet = properties.getProperty("mail.charset") match { case null => "UTF-8" case x => x } // def host_=(hostname: String) = System.setProperty("mail.smtp.host", hostname) protected class MsgSender extends SpecializedLiftActor[MessageInfo] { protected def messageHandler = { case MessageInfo(from, subject, info) => try { msgSendImpl(from, subject, info) } catch { case e: Exception => logger.error("Couldn't send mail", e) } } } protected def performTransportSend(msg: MimeMessage) = { import Props.RunModes._ (Props.mode match { case Development => devModeSend.vend case Test => testModeSend.vend case Staging => stagingModeSend.vend case Production => productionModeSend.vend case Pilot => pilotModeSend.vend case Profile => profileModeSend.vend }).apply(msg) } /** * How to send a message in dev mode. By default, use Transport.send(msg) */ lazy val devModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => Transport.send(m)) {} /** * How to send a message in test mode. By default, log the message */ lazy val testModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => logger.info("Sending Mime Message: "+m)) {} /** * How to send a message in staging mode. By default, use Transport.send(msg) */ lazy val stagingModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => Transport.send(m)) {} /** * How to send a message in production mode. By default, use Transport.send(msg) */ lazy val productionModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => Transport.send(m)) {} /** * How to send a message in pilot mode. By default, use Transport.send(msg) */ lazy val pilotModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => Transport.send(m)) {} /** * How to send a message in profile mode. By default, use Transport.send(msg) */ lazy val profileModeSend: Inject[MimeMessage => Unit] = new Inject[MimeMessage => Unit]((m: MimeMessage) => Transport.send(m)) {} /** * Synchronously send an email. */ def blockingSendMail(from: From, subject: Subject, rest: MailTypes*) { msgSendImpl(from, subject, rest.toList) } def msgSendImpl(from: From, subject: Subject, info: List[MailTypes]) { val session = authenticator match { case Full(a) => jndiSession openOr Session.getInstance(buildProps, a) case _ => jndiSession openOr Session.getInstance(buildProps) } val message = new MimeMessage(session) message.setFrom(from) message.setRecipients(Message.RecipientType.TO, info.flatMap {case x: To => Some[To](x) case _ => None}) message.setRecipients(Message.RecipientType.CC, info.flatMap {case x: CC => Some[CC](x) case _ => None}) message.setRecipients(Message.RecipientType.BCC, info.flatMap {case x: BCC => Some[BCC](x) case _ => None}) // message.setReplyTo(filter[MailTypes, ReplyTo](info, {case x @ ReplyTo(_) => Some(x); case _ => None})) message.setReplyTo(info.flatMap {case x: ReplyTo => Some[ReplyTo](x) case _ => None}) message.setSubject(subject.subject) info.foreach { case MessageHeader(name, value) => message.addHeader(name, value) case _ => } val bodyTypes = info.flatMap {case x: MailBodyType => Some[MailBodyType](x); case _ => None} bodyTypes match { case PlainMailBodyType(txt) :: Nil => message.setText(txt) case _ => val multiPart = new MimeMultipart("alternative") bodyTypes.foreach { tab => val bp = buildMailBody(tab) multiPart.addBodyPart(bp) } message.setContent(multiPart); } Mailer.this.performTransportSend(message) } protected lazy val msgSender = new MsgSender /** * The default mechanism for encoding a NodeSeq to a String representing HTML. By default, use Html5.toString(node) */ protected def encodeHtmlBodyPart(in: NodeSeq): String = Html5.toString(firstNode(in)) protected def firstNode(in: NodeSeq): Node = in match { case n: Node => n case ns => ns.toList.collect { case e: Elem => e } match { case Nil => if (ns.length == 0) Text("") else ns(0) case x :: xs => x } } /** * Given a MailBodyType, convert it to a javax.mail.BodyPart. You can override this method if you * add custom MailBodyTypes */ protected def buildMailBody(tab: MailBodyType): BodyPart = { val bp = new MimeBodyPart tab match { case PlainMailBodyType(txt) => bp.setText(txt, "UTF-8") case PlainPlusBodyType(txt, charset) => bp.setText(txt, charset) case XHTMLMailBodyType(html) => bp.setContent(encodeHtmlBodyPart(html), "text/html; charset=" + charSet) case XHTMLPlusImages(html, img@_*) => val html_mp = new MimeMultipart("related") val bp2 = new MimeBodyPart bp2.setContent(encodeHtmlBodyPart(html), "text/html; charset=" + charSet) html_mp.addBodyPart(bp2) img.foreach { i => val rel_bpi = new MimeBodyPart rel_bpi.setFileName(i.name) rel_bpi.setContentID(i.name) rel_bpi.setDisposition("inline") rel_bpi.setDataHandler(new javax.activation.DataHandler(new javax.activation.DataSource { def getContentType = i.mimeType def getInputStream = new java.io.ByteArrayInputStream(i.bytes) def getName = i.name def getOutputStream = throw new java.io.IOException("Unable to write to item") })) html_mp.addBodyPart(rel_bpi) } bp.setContent(html_mp) } bp } /** * Asynchronously send an email. */ def sendMail(from: From, subject: Subject, rest: MailTypes*) { // forward it to an actor so there's no time on this thread spent sending the message msgSender ! MessageInfo(from, subject, rest.toList) } } Other Lift Framework examples (source code examples)Here is a short list of links related to this Lift Framework Mailer.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.