/*
* Copyright 2014 Effektif GmbH.
*
* 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 com.effektif.email;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
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.MimeMessage.RecipientType;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.effektif.workflow.impl.configuration.Brewery;
import com.effektif.workflow.impl.configuration.Plugin;
/** default impl that sends emails using javax.mail.
*
* @author Tom Baeyens
*/
public class OutgoingEmailServiceImpl implements OutgoingEmailService, Plugin {
private static final Logger log = LoggerFactory.getLogger(OutgoingEmailServiceImpl.class);
protected Properties properties = new Properties();
protected Authenticator authenticator = null;
@Override
public void plugin(Brewery brewery) {
}
public OutgoingEmailServiceImpl() {
properties = new Properties();
property("mail.transport.protocol", "smtp");
host("localhost");
portDefault();
}
public OutgoingEmailServiceImpl host(String hostName) {
properties.put("mail.smtp.host", hostName);
return this;
}
public OutgoingEmailServiceImpl port(int port) {
properties.put("mail.smtp.port", Integer.toString(port));
return this;
}
public OutgoingEmailServiceImpl portDefault() {
port(25);
return this;
}
public OutgoingEmailServiceImpl portDefaultSsl() {
port(465);
return this;
}
public OutgoingEmailServiceImpl portDefaultTls() {
port(587);
return this;
}
public OutgoingEmailServiceImpl ssl() {
portDefaultSsl();
return this;
}
public OutgoingEmailServiceImpl ssl(int port) {
port(port);
properties.put("mail.smtp.socketFactory.port", Integer.toString(port));
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.socketFactory.fallback", "false");
return this;
}
public OutgoingEmailServiceImpl tls() {
portDefaultTls();
properties.setProperty("mail.smtp.starttls.enable", "true");
return this;
}
public OutgoingEmailServiceImpl authenticate(final String username, final String password) {
properties.setProperty("mail.smtp.auth", "true");
this.authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
};
return this;
}
public OutgoingEmailServiceImpl from(String mailSmtpFrom) {
properties.setProperty("mail.smtp.from", mailSmtpFrom);
return this;
}
public OutgoingEmailServiceImpl timeout(long timeout) {
properties.put("mail.smtp.timeout", Long.toString(timeout));
return this;
}
public OutgoingEmailServiceImpl connectionTimeoutSeconds(long connectionTimeoutSeconds) {
if (connectionTimeoutSeconds<=0) {
throw new RuntimeException("Invalid timeout value "+connectionTimeoutSeconds+". Expected positive value expressed in seconds.");
}
properties.put("mail.smtp.connectiontimeout", Long.toString(connectionTimeoutSeconds*1000));
return this;
}
public OutgoingEmailServiceImpl property(String key, String value) {
properties.put(key, value);
return this;
}
@Override
public String validate(String emailAddress) {
return validateEmailAddress(emailAddress);
}
public static String validateEmailAddress(String emailAddress) {
if (emailAddress != null) {
try {
InternetAddress internetAddress = new InternetAddress(emailAddress);
return internetAddress.toUnicodeString();
} catch (AddressException e) {
log.error("Invalid mail address: " + emailAddress, e);
}
}
return null;
}
@Override
public void send(OutgoingEmail email) {
try {
Session session = getSession();
MimeMessage message = createMessage(session, email);
if (isValid(email)) {
log.debug("Sending email to "+email.getTo()+" with "+properties.get("mail.smtp.host"));
Transport.send(message);
}
} catch (MessagingException | IOException e) {
log.error("Problem sending email: "+e.getMessage());
if (properties!=null) {
for (Object key: properties.keySet()) {
log.error(key+"="+properties.get(key));
}
}
throw new RuntimeException("Problem sending email: "+e.getMessage(), e);
}
}
protected boolean isValid(OutgoingEmail email) {
if (email.getTo()==null || email.getTo().isEmpty() || email.getTo().contains(null)) {
log.error("NOT sending mail: no TO recipients specified");
return false;
}
return true;
}
protected MimeMessage createMessage(Session session, OutgoingEmail email) throws AddressException, MessagingException, IOException {
MimeMessage message = new MimeMessage(session);
Map<String, String> headers = email.getHeaders();
if (headers!=null) {
for (String header: headers.keySet()) {
String value = headers.get(header);
message.addHeader(header, value);
}
}
if (email.getFrom()!=null) {
email.setFrom(email.getFrom());
}
if (email.getTo()!=null) {
for (String to: email.getTo()) {
message.addRecipient(RecipientType.TO, createAddress(to));
}
}
if (email.getCc()!=null) {
for (String cc: email.getCc()) {
message.addRecipient(RecipientType.CC, createAddress(cc));
}
}
if (email.getBcc()!=null) {
for (String bcc: email.getBcc()) {
message.addRecipient(RecipientType.BCC, createAddress(bcc));
}
}
if (email.getSubject()!=null) {
message.setSubject(email.getSubject());
}
MimeMultipart content = new MimeMultipart();
if (email.getBodyText()!=null) {
MimeBodyPart part = createBodyPartText(email.getBodyText());
content.addBodyPart(part);
}
if (email.getBodyHtml()!=null) {
MimeBodyPart part = createBodyPartHtml(email.getBodyHtml());
content.addBodyPart(part);
}
if (email.getAttachments()!=null) {
for (Attachment attachment: email.getAttachments()) {
MimeBodyPart part = createBodyPartAttachment(attachment);
content.addBodyPart(part);
}
}
message.setContent(content);
return message;
}
protected MimeBodyPart createBodyPartText(String bodyText) throws MessagingException {
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(bodyText, "text/plain; charset=utf-8");
return bodyPart;
}
protected MimeBodyPart createBodyPartHtml(String bodyHtml) throws MessagingException {
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(bodyHtml, "text/html; charset=utf-8");
return bodyPart;
}
protected MimeBodyPart createBodyPartAttachment(Attachment attachment) throws IOException, MessagingException {
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setFileName(attachment.getFileName());
DataSource dataSource = new ByteArrayDataSource(attachment.getInputStream(), attachment.getContentType());
bodyPart.setDataHandler(new DataHandler(dataSource));
return bodyPart;
}
protected Address createAddress(String emailAddress) throws AddressException {
return new InternetAddress(emailAddress);
}
public Session getSession() {
return Session.getInstance(properties, authenticator);
}
}