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

com.github.jurajburian.mailer.Mailer.scala Maven / Gradle / Ivy

package com.github.jurajburian.mailer

import java.io.File

import javax.activation.{DataHandler, FileDataSource}
import javax.mail.internet.{InternetAddress, MimeBodyPart, MimeMultipart, PreencodedMimeBodyPart}
import javax.mail.util.ByteArrayDataSource
import javax.mail.{MessagingException, Session, Transport}


/**
	* Represents the content of the e-mail message, composed of individual `MimeBodyPart` instances.
	* For easier use, helper methods to add specific content are available, such as `html()` for
	* adding ''HTML'' or `attachFile()` to add file attachment.
	*
	* @param parts parts of the message content (represented by `MimeBodyPart` instances)
	*/
case class Content(parts: MimeBodyPart*) {

	/**
		* Appends the given part (represented by `MimeBodyPart` instance) to the existing content parts.
		*
		* @param parts content part to append
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		*/
	def append(parts: MimeBodyPart*) = Content(this.parts ++ parts: _*)

	/**
		* Appends the given string as the text content part (defaults to ''text/plain'').
		*
		* @param text    text to append
		* @param charset charset of the given text (defaults to ''UTF-8'')
		* @param subtype defines subtype of the ''MIME type'' (the part after the slash), defaults
		*                to ''UTF-8''
		* @param headers content part headers (''RFC 822'')
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		*/
	def text(text: String, charset: String = "UTF-8", subtype: String = "plain",
					 headers: Seq[MessageHeader] = Seq.empty[MessageHeader]): Content = {

		val part = new MimeBodyPart()
		part.setText(text, charset, subtype)
		headers.foreach(header => part.setHeader(header.name, header.value))
		append(part)
	}

	/**
		* Appends the given ''HTML'' string as the new ''HTML'' content part.
		*
		* @param html    ''HTML'' string to append
		* @param charset charset of the given ''HTML'' string (defaults to ''UTF-8'')
		* @param headers content part headers (''RFC 822'')
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		*/
	def html(html: String, charset: String = "UTF-8",
					 headers: Seq[MessageHeader] = Seq.empty[MessageHeader]): Content = {

		val part = new MimeBodyPart()
		part.setText(html, charset, "html")
		headers.foreach(header => part.setHeader(header.name, header.value))
		append(part)
	}

	/**
		* Appends the given file as the e-mail message attachment.
		*
		* @param file      file to attach
		* @param name      name of the attachment (optional, defaults to the given file name)
		* @param contentId the "Content-ID" header field of this body part
		* @param headers   content part headers (''RFC 822'')
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		*/

	def attachFile(file: File, name: Option[String] = None,
								 contentId: Option[String] = None,
								 headers: Seq[MessageHeader] = Seq.empty[MessageHeader]): Content = {

		val part = new MimeBodyPart()
		contentId.foreach(part.setContentID)
		part.setDataHandler(new DataHandler(new FileDataSource(file)))
		part.setFileName(name.getOrElse(file.getName))
		headers.foreach(header => part.setHeader(header.name, header.value))
		append(part)
	}

	/**
		* Appends the given array of bytes as the e-mail message attachment. Useful especially when the
		* original file object is not available, only its array of bytes.
		*
		* @param bytes     array of bytes representing the attachment
		* @param mimeType  ''MIME type'' of the attachment
		* @param name      name of the attachment (optional)
		* @param contentId the "Content-ID" header field of this body part (optional)
		* @param headers   content part headers (''RFC 822'')
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		*/
	def attachBytes(bytes: Array[Byte], mimeType: String, name: Option[String] = None,
									contentId: Option[String] = None,
									headers: Seq[MessageHeader] = Seq.empty[MessageHeader]): Content = {

		val part = new MimeBodyPart()
		contentId.foreach(part.setContentID)
		part.setDataHandler(new DataHandler(new ByteArrayDataSource(bytes, mimeType)))
		name.foreach(part.setFileName)
		headers.foreach(header => part.setHeader(header.name, header.value))
		append(part)
	}


	/**
		* Appends the given string of ''Base64-encoded'' data as the e-mail message attachment. Use
		* instead of the `#attachBytes` method if you have already ''Base64-encoded'' data and you
		* want to avoid ''JavaMail'' encoding it again.
		*
		* @param data      ''Base64-encoded'' data
		* @param mimeType  ''MIME type'' of the attachment
		* @param name      name of the attachment (optional)
		* @param contentId the `Content-ID` header field of this body part (optional)
		* @param headers   content part headers (''RFC 822'')
		* @return instance of the [[com.github.jurajburian.mailer.Content]] class with appended
		*         content part
		* @see http://www.oracle.com/technetwork/java/faq-135477.html#preencoded
		*/
	def attachBase64(data: String, mimeType: String, name: Option[String] = None,
									 contentId: Option[String] = None,
									 headers: Seq[MessageHeader] = Seq.empty[MessageHeader]): Content = {

		val part = new PreencodedMimeBodyPart("base64")
		contentId.foreach(part.setContentID)
		part.setDataHandler(new DataHandler(new ByteArrayDataSource(data, mimeType)))
		name.foreach(part.setFileName)
		headers.foreach(header => part.setHeader(header.name, header.value))
		append(part)
	}


	@throws[MessagingException]
	def apply() = {
		val prts = parts
		new MimeMultipart() {
			prts.foreach(addBodyPart(_))
		}
	}
}

/**
	* Represents the e-mail message itself.
	*
	* @param from       e-mail sender address
	* @param subject    e-mail subject text
	* @param content    e-mail content, represented by the instance of
	*                   [[com.github.jurajburian.mailer.Content]] class
	* @param to         set of e-mail receiver addresses
	* @param cc         set of e-mail ''carbon copy'' receiver addresses
	* @param bcc        set of e-mail ''blind carbon copy'' receiver addresses
	* @param replyTo    address used to reply this message (optional)
	* @param replyToAll whether the new message will be addressed to all recipients of this message
	* @param headers    message headers (''RFC 822'')
	*/
case class Message(from: InternetAddress,
									 subject: String,
									 content: Content,
									 to: Seq[InternetAddress] = Seq.empty[InternetAddress],
									 cc: Seq[InternetAddress] = Seq.empty[InternetAddress],
									 bcc: Seq[InternetAddress] = Seq.empty[InternetAddress],
									 replyTo: Option[InternetAddress] = None,
									 replyToAll: Option[Boolean] = None,
									 headers: Seq[MessageHeader] = Seq.empty[MessageHeader]) {

}

/**
	* Represents the ''Mailer'' itself, with methods for opening/closing the connection and sending
	* the message ([[com.github.jurajburian.mailer.Message]])
	*/
trait Mailer {

	/**
		* Creates new transport connection.
		*
		* @return instance of the [[com.github.jurajburian.mailer.Mailer]] itself
		*/
	@throws[MessagingException]
	def connect(): Mailer

	/**
		* Sends the given message.
		*
		* @param msg message to send
		* @return instance of the [[com.github.jurajburian.mailer.Mailer]] itself
		*/
	@throws[MessagingException]
	def send(msg: Message): Mailer

	/**
		* Returns the instance of `javax.mail.Transport`, used by this instance of 'Mailer'
		*
		* @return instance of `javax.mail.Transport`
		*/
	def transport: Transport

	/**
		* Closes the previously opened transport connection.
		*
		* @return instance of the [[com.github.jurajburian.mailer.Mailer]] itself
		*/
	@throws[MessagingException]
	def close(): Mailer
}


/**
	* ''Mailer'' object providing default operations to handle the transport connection and send the
	* e-mail message.
	*
	* @author jubu
	*/
object Mailer {

	import MailKeys._

	/**
		* Sets the ''JavaMail'' session to the ''Mailer'' and returns the instance ready to send e-mail
		* messages. Optionally, transport method can be explicitly specified.
		*
		* @param session      ''JavaMail'' session
		* @param transportOpt transport method (optional)
		* @return ''Mailer'' instance
		*/
	def apply(session: Session, transportOpt: Option[Transport] = None) = new Mailer {


		val trt = transportOpt match {
			case None => if (session.getProperty(TransportProtocolKey) == null) {
				session.getTransport("smtp")
			} else {
				session.getTransport
			}
			case Some(t) => t
		}

		@throws[MessagingException]
		override def connect(): Mailer = {
			if (!trt.isConnected) {
				trt.connect()
			}
			this
		}

		@throws[MessagingException]
		override def send(msg: Message): Mailer = {
			import javax.mail.{Message => M}
			connect()
			val message = new MimeMessage(session)
			msg.to.foreach(message.addRecipient(M.RecipientType.TO, _))
			msg.cc.foreach(message.addRecipient(M.RecipientType.CC, _))
			msg.bcc.foreach(message.addRecipient(M.RecipientType.BCC, _))
			msg.headers.foreach(header => message.setHeader(header.name, header.value))
			message.setSubject(msg.subject)
			message.setFrom(msg.from)
			message.setContent(new MimeMultipart() {
				msg.content.parts.foreach(addBodyPart(_))
			})
			trt.sendMessage(message, message.getAllRecipients)
			this
		}

		override def transport: Transport = trt

		@throws[MessagingException]
		override def close(): Mailer = {
			if (trt.isConnected) {
				trt.close()
			}
			this
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy