package com.im.imjutil.email;
import java.io.File;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import com.im.imjutil.config.Configurator;
import com.im.imjutil.exception.EmailException;
import com.im.imjutil.logging.Logger;
import com.im.imjutil.validation.Convert;
import com.im.imjutil.validation.Validator;
/**
* Classe responsavel pelo envio de emails do sistema.<br>
* Para enviar um email, crie e preencha um objeto da classe {@link Email}
* e use o metodo estatico <code>send()</code>.
*
* @author Felipe Zappala
*/
public class EmailSender {
/** Sender padrao do sistema */
private static final EmailSender defaultSender;
static {
defaultSender = new EmailSender();
}
private boolean debug;
private Authenticator authenticator;
private Properties properties;
private String sender;
private Queue<Email> queue;
/**
* Construtor do {@link EmailSender}.
* <br>
* Este utiliza as propriedades de envio configuradas no arquivo
* de configuracoes globais {@code config.properties}.
*/
public EmailSender() {
this(getDefaultProperties());
}
/**
* Construtor do {@link EmailSender}.
* <br>
* Obtem as propriedades de envio de um {@link Properties} personalizado.
*
* @param properties Arquivo de propriedades de envio.
*/
public EmailSender(Properties properties) {
validate(properties);
this.properties = properties;
this.debug = Boolean.valueOf(getProperty("email.debug"));
this.sender = getProperty("email.smtp.sender.address");
this.queue = new LinkedList<Email>();
this.authenticator = getAuthenticator(this.properties);
}
/**
* Obtem as propriedades padroes configuradas no config.properties.
*/
private static Properties getDefaultProperties() {
Properties p = new Properties();
p.put("email.smtp.auth", Configurator
.getProperty("email.smtp.auth"));
p.put("email.debug", Configurator
.getProperty("email.debug"));
p.put("email.smtp.host", Configurator
.getProperty("email.smtp.host"));
p.put("email.smtp.port", Configurator
.getProperty("email.smtp.port"));
p.put("email.smtp.socket.port", Configurator
.getProperty("email.smtp.socket.port"));
p.put("email.smtp.socket.factory", Configurator
.getProperty("email.smtp.socket.factory"));
p.put("email.smtp.sender.address", Configurator
.getProperty("email.smtp.sender.address"));
p.put("email.smtp.sender.password", Configurator
.getProperty("email.smtp.sender.password"));
return p;
}
/**
* Valida todas as propriedades necessarias e reconfigura o
* arquivo para as necessidades da lib do java.
*/
private void validate(Properties p) {
StringBuilder sb = new StringBuilder();
p.put("mail.smtp.socketFactory.fallback", "false");
if (!Validator.isValid(p.getProperty("email.smtp.sender.address"))) {
sb.append("email.smtp.sender.address; ");
}
if (!Validator.isValid(p.getProperty("email.smtp.sender.password"))) {
sb.append("email.smtp.sender.password; ");
}
if (!Validator.isValid(p.getProperty("email.debug"))) {
sb.append("email.debug; ");
} else {
p.put("mail.debug", p.getProperty("email.debug"));
}
if (!Validator.isValid(p.getProperty("email.smtp.auth"))) {
sb.append("email.smtp.auth; ");
} else {
p.put("mail.smtp.auth", p.getProperty("email.smtp.auth"));
}
if (!Validator.isValid(p.getProperty("email.smtp.host"))) {
sb.append("email.smtp.host; ");
} else {
p.put("mail.smtp.host", p.getProperty("email.smtp.host"));
}
if (!Validator.isValid(p.getProperty("email.smtp.socket.port"))) {
sb.append("email.smtp.socket.port; ");
} else {
p.put("mail.smtp.port", p.getProperty("email.smtp.port"));
}
if (!Validator.isValid(p.getProperty("email.smtp.socket.port"))) {
sb.append("email.smtp.socket.port; ");
} else {
p.put("mail.smtp.socketFactory.port",
p.getProperty("email.smtp.socket.port"));
}
if (Validator.isValid(p.getProperty("email.smtp.socket.factory"))) {
p.put("mail.smtp.socketFactory.class",
p.getProperty("email.smtp.socket.factory"));
}
if (sb.length() > 0) {
throw new EmailException(Convert.toString(
"Propriedades requiridas nao encontradas: ", sb));
}
}
/**
* Metodo utilitario para envios rapidos de email.
* <br>
* Para o email ser enviado deve-se ter no minimo um endereco de destino.
*
* @param subject O assunto do email. Pode ser nulo ou vazio.
* @param message A mensagem do email. Pode ser nulo ou vazio.
* @param to Um ou varios enderecos de destino do email.
* @throws EmailException Caso ocorra algum erro no envio.
*/
public static void send(String subject, String message, String... to)
throws EmailException {
Email email = new Email(to);
email.setSubject(subject);
email.setMessage(message);
defaultSender.sendEmail(email);
}
/**
* Envia um email utilizando o construtor {@link #EmailSender()}.
* <br>
* Para o email ser enviado deve-se ter no minimo um endereco de destino.
*
* @param email O email a ser enviado.
* @throws EmailException Caso ocorra algum erro no envio.
*/
public static void send(Email email) throws EmailException {
defaultSender.sendEmail(email);
}
/**
* Envia um email.<br>
* Para o email ser enviado deve-se ter no minimo um endereco de destino.
*
* @param email O email a ser enviado.
* @throws EmailException Caso ocorra algum erro no envio.
*/
private void sendEmail(Email email) throws EmailException {
Logger.debug("[EmailSender] Enviando email: ", email);
try {
Message message = new MimeMessage(getSession());
message.setFrom(new InternetAddress(sender));
message.setRecipients(RecipientType.BCC, getRecipients(email));
message.setSubject(email.getSubject());
MimeMultipart contentRoot = new MimeMultipart("mixed");
MimeMultipart contentBody = new MimeMultipart("alternative");
MimeBodyPart contentRootPart = new MimeBodyPart();
contentRootPart.setContent(contentBody);
contentRoot.addBodyPart(contentRootPart);
MimeBodyPart contentMessage = new MimeBodyPart();
contentMessage.setDisposition(Part.INLINE);
contentMessage.setText(email.getMessage(), null, "html");
contentBody.addBodyPart(contentMessage);
if (email.hasAttachments()) {
for (File file : email.getAttachments()) {
MimeBodyPart contentAttachtment = new MimeBodyPart();
DataSource ds = new FileDataSource(file);
contentAttachtment.setDisposition(Part.ATTACHMENT);
contentAttachtment.setDataHandler(new DataHandler(ds));
contentAttachtment.setFileName(file.getName());
contentRoot.addBodyPart(contentAttachtment);
}
}
message.setContent(contentRoot);
Transport.send(message);
} catch (Exception e) {
Logger.error(e, "[EmailSender] Erro ao enviar o email!", email);
throw new EmailException(Convert.toString(
"Erro ao enviar o email: ", email), e);
}
Logger.debug("[EmailSender] Email enviado com sucesso: ", email);
}
/**
* Obtem uma propriedade do arquivo de configuracao.
*
* @param key O nome da propriedade.
* @return O valor da propriedade.
*/
private String getProperty(String key) {
return this.properties.getProperty(key);
}
/**
* Obtem uma sessao de envio.
*
* @return Uma sessao de envio.
*/
private Session getSession() {
Session session = Session.getInstance(properties, authenticator);
session.setDebug(debug);
return session;
}
/**
* Obtem os enderecos de email dos destinatarios.
*/
private static Address[] getRecipients(Email email) throws Exception {
Set<String> ends = email.getTo();
Address[] address = new InternetAddress[ends.size()];
int i = 0;
for (String end : ends) {
if (Validator.isEmail(end)) {
address[i++] = new InternetAddress(end);
}
}
return address;
}
/**
* Obtem o autenticador do email de envio.
*/
private static Authenticator getAuthenticator(Properties props) {
final String user = props.getProperty("email.smtp.sender.address");
final String pass = props.getProperty("email.smtp.sender.password");
return new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, pass);
}
};
}
/**
* Adiciona emails a fila de envio.
*/
public EmailSender add(Email email) {
if (email != null) {
this.queue.offer(email);
}
return this;
}
/**
* Envia todos os emails da fila.
*/
public EmailSender send() {
while (!this.queue.isEmpty()) {
this.sendEmail(this.queue.poll());
}
return this;
}
}