blob: 6e6dd69d774fd662c47a3f852b6cd8a325d3f0ae [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.openmeetings.utils.mail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
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 javax.mail.util.ByteArrayDataSource;
import org.apache.openmeetings.OpenmeetingsVariables;
import org.apache.openmeetings.data.basic.dao.ConfigurationDao;
import org.apache.openmeetings.data.basic.dao.MailMessageDao;
import org.apache.openmeetings.persistence.beans.basic.MailMessage;
import org.apache.openmeetings.persistence.beans.basic.MailMessage.Status;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
/**
*
* @author swagner
*
*/
public class MailHandler {
private static final Logger log = Red5LoggerFactory.getLogger(
MailHandler.class, OpenmeetingsVariables.webAppRootKey);
private static final int MAIL_SEND_TIMEOUT = 60 * 60 * 1000; // 1 hour
private static final int MAXIMUM_ERROR_COUNT = 5;
@Autowired
private ConfigurationDao cfgDao;
@Autowired
private TaskExecutor taskExecutor;
@Autowired
private MailMessageDao mailMessageDao;
private String smtpServer;
private String smtpPort;
private String from;
private String mailAuthUser;
private String mailAuthPass;
private boolean mailTls;
private boolean mailAddReplyTo;
private void init() {
smtpServer = cfgDao.getConfValue("smtp_server", String.class, null);
smtpPort = cfgDao.getConfValue("smtp_port", String.class, "25");
from = cfgDao.getConfValue("system_email_addr", String.class, null);
mailAuthUser = cfgDao.getConfValue("email_username", String.class, null);
mailAuthPass = cfgDao.getConfValue("email_userpass", String.class, null);
mailTls = "1".equals(cfgDao.getConfValue("mail.smtp.starttls.enable", String.class, "0"));
mailAddReplyTo = "1".equals(cfgDao.getConfValue("inviter.email.as.replyto", String.class, "1"));
}
protected MimeMessage appendIcsBody(MimeMessage msg, MailMessage m) throws Exception {
log.debug("setMessageBody for iCal message");
// -- Create a new message --
Multipart multipart = new MimeMultipart();
Multipart multiBody = new MimeMultipart("alternative");
BodyPart html = new MimeBodyPart();
html.setDataHandler(new DataHandler(new ByteArrayDataSource(m.getBody(), "text/html; charset=UTF-8")));
multiBody.addBodyPart(html);
BodyPart iCalContent = new MimeBodyPart();
iCalContent.addHeader("content-class", "urn:content-classes:calendarmessage");
iCalContent.setDataHandler(new DataHandler(new ByteArrayDataSource(new ByteArrayInputStream(m.getIcs()),
"text/calendar; charset=UTF-8; method=REQUEST")));
multiBody.addBodyPart(iCalContent);
BodyPart body = new MimeBodyPart();
body.setContent(multiBody);
multipart.addBodyPart(body);
BodyPart iCalAttachment = new MimeBodyPart();
iCalAttachment.setDataHandler(new DataHandler(new ByteArrayDataSource(new ByteArrayInputStream(m.getIcs()),
"application/ics")));
iCalAttachment.removeHeader("Content-Transfer-Encoding");
iCalAttachment.addHeader("Content-Transfer-Encoding", "base64");
iCalAttachment.removeHeader("Content-Type");
iCalAttachment.addHeader("Content-Type", "application/ics");
iCalAttachment.setFileName("invite.ics");
multipart.addBodyPart(iCalAttachment);
msg.setContent(multipart);
return msg;
}
private MimeMessage appendBody(MimeMessage msg, MailMessage m) throws MessagingException, IOException {
// -- Set the subject and body text --
msg.setDataHandler(new DataHandler(new ByteArrayDataSource(m.getBody(), "text/html; charset=\"utf-8\"")));
// -- Set some other header information --
msg.setHeader("X-Mailer", "XML-Mail");
msg.setSentDate(new Date());
return msg;
}
private MimeMessage getBasicMimeMessage() throws Exception {
log.debug("getBasicMimeMessage");
if (smtpServer == null) {
init();
}
Properties props = new Properties(System.getProperties());
props.put("mail.smtp.host", smtpServer);
props.put("mail.smtp.port", smtpPort);
if (mailTls) {
props.put("mail.smtp.starttls.enable", "true");
}
// Check for Authentication
Session session = null;
if (mailAuthUser != null && mailAuthUser.length() > 0
&& mailAuthPass != null && mailAuthPass.length() > 0) {
// use SMTP Authentication
props.put("mail.smtp.auth", "true");
session = Session.getInstance(props, new SmtpAuthenticator(mailAuthUser, mailAuthPass));
} else {
// not use SMTP Authentication
session = Session.getInstance(props, null);
}
// Building MimeMessage
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
return msg;
}
private MimeMessage getMimeMessage(MailMessage m) throws Exception {
log.debug("getMimeMessage");
// Building MimeMessage
MimeMessage msg = getBasicMimeMessage();
msg.setSubject(m.getSubject());
String replyTo = m.getReplyTo();
if (replyTo != null && mailAddReplyTo) {
log.debug("setReplyTo " + replyTo);
if (MailUtil.matches(replyTo)) {
msg.setReplyTo(new InternetAddress[]{new InternetAddress(replyTo)});
}
}
msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse(m.getRecipients(), false));
return m.getIcs() == null ? appendBody(msg, m) : appendIcsBody(msg, m);
}
public void send(String toEmail, String subj, String message) {
send(toEmail, null, subj, message);
}
public void send(String toEmail, String replyTo, String subj, String message) {
send(new MailMessage(toEmail, replyTo, subj, message));
}
public void send(MailMessage m) {
send(m, false);
}
public void send(final MailMessage m, boolean send) {
if (send) {
if (m.getId() != null) {
m.setStatus(Status.SENDING);
mailMessageDao.update(m, null);
}
taskExecutor.execute(new Runnable() {
public void run() {
log.debug("Message sending in progress");
log.debug(" To: " + m.getRecipients());
log.debug(" Subject: " + m.getSubject());
// -- Send the message --
try {
Transport.send(getMimeMessage(m));
m.setLastError("");
m.setStatus(Status.DONE);
} catch (Exception e) {
log.error("Error while sending message", e);
m.setErrorCount(m.getErrorCount() + 1);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.close();
m.setLastError(sw.getBuffer().toString());
m.setStatus(m.getErrorCount() < MAXIMUM_ERROR_COUNT ? Status.NONE : Status.ERROR);
}
if (m.getId() != null) {
mailMessageDao.update(m, null);
}
}
});
} else {
m.setStatus(Status.NONE);
mailMessageDao.update(m, null);
}
}
public void resetSendingStatus() {
log.debug("resetSendingStatus enter ...");
Calendar c = Calendar.getInstance();
c.add(Calendar.MILLISECOND, -MAIL_SEND_TIMEOUT);
mailMessageDao.resetSendingStatus(c);
log.debug("... resetSendingStatus done.");
}
public void sendMails() throws Exception {
init();
log.debug("sendMails enter ...");
List<MailMessage> list = mailMessageDao.get(0, 1);
while (!list.isEmpty()) {
send(list.get(0), true);
list = mailMessageDao.get(0, 1);
}
log.debug("... sendMails done.");
}
}