// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.service;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import com.google.common.collect.Sets;
import edu.harvard.med.screensaver.util.StringUtils;
import org.apache.commons.cli.OptionBuilder;
import org.apache.log4j.Logger;
/**
* SMTP EmailService implementation
* TODO: rework this class using a builder patter for creation of the message (to better handle multipart messages).
*/
public class SmtpEmailService implements EmailService
{
private static Logger log = Logger.getLogger(SmtpEmailService.class);
// member variables used if instantiated as a service
private String host;
private String username;
private String password;
private boolean useSmtps;
private InternetAddress [] replyTos;
public SmtpEmailService(String host, String username, String replyTos) throws AddressException
{
this(host,username, replyTos, null,false);
}
/**
* @motivation for Spring instantiation
* @param host mail server host i.e. smtp.cl.med.harvard.edu
* @param username mail account name
* @param password password, can be blank if unnecessary
* @throws AddressException
*/
public SmtpEmailService(String host, String username, String replyTos, String password) throws AddressException
{
this(host,username, replyTos, password,false);
}
/**
* @param useSmtps in order to use smtp.gmail.com (for testing)
* @throws AddressException
*/
public SmtpEmailService(String host, String username, String replyTos, String password, boolean useSmtps) throws AddressException
{
this.host = host;
this.username = username;
this.password = password;
this.useSmtps = useSmtps;
if(replyTos != null)
{
String[] sreplyTos = replyTos.split(",");
Set<InternetAddress> set = Sets.newHashSet();
for(String s:sreplyTos) {
if(!StringUtils.isEmpty(s)) set.add(new InternetAddress(s));
}
this.replyTos = set.toArray(new InternetAddress[] {} );
}
}
public void send(String subject,
String message,
InternetAddress from,
InternetAddress[] recipients,
InternetAddress[] cclist) throws MessagingException
{
try {
send(subject, message, from, recipients, cclist, null);
}
catch (IOException e) {
throw new RuntimeException("should not happen as there is no file attachment", e);
}
}
public void send(String subject,
String message,
InternetAddress from,
InternetAddress[] recipients,
InternetAddress[] cclist,
File attachedFile) throws MessagingException, IOException
{
sendMessage(subject, message, from, recipients, cclist, attachedFile);
}
public void send(String subject,
String message,
String from,
String[] recipients,
String[] cclist) throws MessagingException
{
try {
send(subject, message, from, recipients, cclist, null);
}
catch (IOException e) {
throw new RuntimeException("should not happen as there is no file attachment", e);
}
}
public void send(String subject,
String message,
String from,
String[] recipients,
String[] cclist,
File attachedFile) throws MessagingException, IOException
{
sendMessage(subject, message, from, recipients, cclist, attachedFile);
}
/**
* Convert string email addresses to proper InternetAddress
*
* @throws IOException
*/
private void sendMessage(
String subject,
String message,
String from,
String[] srecipients,
String[] scclist,
File attachedFile
)
throws MessagingException, IOException
{
InternetAddress[] recipients = new InternetAddress[srecipients.length];
int i = 0;
for(String r:srecipients)
{
recipients[i++] = new InternetAddress(r);
}
InternetAddress[] cclist = null;
i = 0;
if(scclist != null)
{
cclist = new InternetAddress[scclist.length];
for(String r:scclist)
{
cclist[i++]= new InternetAddress(r);
}
}
sendMessage(subject, message, new InternetAddress(from), recipients, cclist, attachedFile);
}
private void sendMessage(
String subject,
String message,
InternetAddress from,
InternetAddress[] recipients,
InternetAddress[] cclist,
File attachedFile
)
throws MessagingException, IOException
{
log.info("try to send: " +
printEmail(subject, message, from, this.replyTos, recipients, cclist, (attachedFile == null ? "" : "" + attachedFile.getCanonicalFile())));
log.info("host: " + host + ", useSMTPS: " + useSmtps);
Properties props = new Properties();
String protocol = "smtp";
if(useSmtps) // need smtps to test with gmail
{
props.put("mail.smtps.auth", "true");
protocol = "smtps";
}
Session session = Session.getDefaultInstance(props, null);
Transport t = session.getTransport(protocol);
try {
MimeMessage msg = new MimeMessage(session);
if(this.replyTos != null) msg.setReplyTo(replyTos);
msg.setFrom(from);
msg.setSubject(subject);
if (attachedFile != null) {
setFileAsAttachment(msg, message, attachedFile);
}
else {
msg.setContent(message, "text/plain");
}
msg.addRecipients(Message.RecipientType.TO, recipients );
if (cclist != null) msg.addRecipients(Message.RecipientType.CC, cclist);
t.connect(host, username, password);
t.sendMessage(msg, msg.getAllRecipients());
}
finally {
t.close();
}
log.info("sent: " +
printEmailHeader(subject, from, this.replyTos, recipients, cclist, (attachedFile == null ? "" : "" + attachedFile.getCanonicalFile())));
}
// Set a file as an attachment. Uses JAF FileDataSource.
// from http://en.wikipedia.org/wiki/Javamail
private static void setFileAsAttachment(Message msg, String message, File file)
throws MessagingException
{
MimeBodyPart p1 = new MimeBodyPart();
p1.setText(message);
// Create second part
MimeBodyPart p2 = new MimeBodyPart();
// Put a file in the second part
FileDataSource fds = new FileDataSource(file);
p2.setDataHandler(new DataHandler(fds));
p2.setFileName(fds.getName());
// Create the Multipart. Add BodyParts to it.
Multipart mp = new MimeMultipart();
mp.addBodyPart(p1);
mp.addBodyPart(p2);
// Set Multipart as the message's content
msg.setContent(mp);
}
// // Set a single part html content.
// // Sending data of any type is similar.
// // from http://en.wikipedia.org/wiki/Javamail
// private static void setHTMLContent(Message msg) throws MessagingException
// {
//
// String html = "<html><head><title>" +
// msg.getSubject() +
// "</title></head><body><h1>" +
// msg.getSubject() +
// "</h1><p>This is a test of sending an HTML e-mail" +
// " through Java.</body></html>";
//
// // HTMLDataSource is an inner class
// msg.setDataHandler(new DataHandler(new HTMLDataSource(html)));
// }
//
// /*
// * Inner class to act as a JAF datasource to send HTML e-mail content
// */
// static class HTMLDataSource implements DataSource {
// private String html;
//
// public HTMLDataSource(String htmlString) {
// html = htmlString;
// }
//
// // Return html string in an InputStream.
// // A new stream must be returned each time.
// public InputStream getInputStream() throws IOException {
// if (html == null) throw new IOException("Null HTML");
// return new ByteArrayInputStream(html.getBytes());
// }
//
// public OutputStream getOutputStream() throws IOException {
// throw new IOException("This DataHandler cannot write HTML");
// }
//
// public String getContentType() {
// return "text/html";
// }
//
// public String getName() {
// return "JAF text/html dataSource to send e-mail only";
// }
// }
/**
* For logging
*/
public static String printEmail(String subject,
String message,
InternetAddress from,
InternetAddress[] replyTos,
InternetAddress[] recipients,
InternetAddress[] cclist, String attachedFilePath)
{
return printEmailHeader(subject, from, replyTos, recipients, cclist, attachedFilePath)
+ "\n========message========\n" + message;
}
public static String printEmailHeader(String subject,
InternetAddress from,
InternetAddress[] replyTos,
InternetAddress[] recipients,
InternetAddress[] cclist,
String attachedFilePath)
{
return "\nSubject: " + subject
+ "\nFrom: " + from
+ "\nReplyTo's: " + (replyTos == null ? "" : com.google.common.base.Joiner.on(',').join(replyTos))
+ "\nTo: " + com.google.common.base.Joiner.on(',').join(recipients)
+ "\nCC: " + (cclist == null ? "" : com.google.common.base.Joiner.on(',').join(cclist))
+ "\nAttached File: " + attachedFilePath;
}
}