From f66e89662c091e082bd1d2feb6ac91513ccff273 Mon Sep 17 00:00:00 2001 From: Rafael Cavazin <rafaelcavazin@gmail.com> Date: Sun, 21 Jul 2013 09:59:00 -0400 Subject: [PATCH] Merge branch 'master' of https://github.com/gitblit/gitblit --- src/main/java/com/gitblit/MailExecutor.java | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 226 insertions(+), 0 deletions(-) diff --git a/src/main/java/com/gitblit/MailExecutor.java b/src/main/java/com/gitblit/MailExecutor.java new file mode 100644 index 0000000..c4e776a --- /dev/null +++ b/src/main/java/com/gitblit/MailExecutor.java @@ -0,0 +1,226 @@ +/* + * Copyright 2011 gitblit.com. + * + * 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.gitblit; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.regex.Pattern; + +import javax.mail.Authenticator; +import javax.mail.Message; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.utils.StringUtils; + +/** + * The mail executor handles sending email messages asynchronously from queue. + * + * @author James Moger + * + */ +public class MailExecutor implements Runnable { + + private final Logger logger = LoggerFactory.getLogger(MailExecutor.class); + + private final Queue<Message> queue = new ConcurrentLinkedQueue<Message>(); + + private final Session session; + + private final IStoredSettings settings; + + public MailExecutor(IStoredSettings settings) { + this.settings = settings; + + final String mailUser = settings.getString(Keys.mail.username, null); + final String mailPassword = settings.getString(Keys.mail.password, null); + final boolean smtps = settings.getBoolean(Keys.mail.smtps, false); + boolean authenticate = !StringUtils.isEmpty(mailUser) && !StringUtils.isEmpty(mailPassword); + String server = settings.getString(Keys.mail.server, ""); + if (StringUtils.isEmpty(server)) { + session = null; + return; + } + int port = settings.getInteger(Keys.mail.port, 25); + boolean isGMail = false; + if (server.equals("smtp.gmail.com")) { + port = 465; + isGMail = true; + } + + Properties props = new Properties(); + props.setProperty("mail.smtp.host", server); + props.setProperty("mail.smtp.port", String.valueOf(port)); + props.setProperty("mail.smtp.auth", String.valueOf(authenticate)); + props.setProperty("mail.smtp.auths", String.valueOf(authenticate)); + + if (isGMail || smtps) { + props.setProperty("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.socketFactory.port", String.valueOf(port)); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.fallback", "false"); + } + + if (!StringUtils.isEmpty(mailUser) && !StringUtils.isEmpty(mailPassword)) { + // SMTP requires authentication + session = Session.getInstance(props, new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + PasswordAuthentication passwordAuthentication = new PasswordAuthentication( + mailUser, mailPassword); + return passwordAuthentication; + } + }); + } else { + // SMTP does not require authentication + session = Session.getInstance(props); + } + } + + /** + * Indicates if the mail executor can send emails. + * + * @return true if the mail executor is ready to send emails + */ + public boolean isReady() { + return session != null; + } + + + /** + * Create a message. + * + * @param toAddresses + * @return a message + */ + public Message createMessage(String... toAddresses) { + return createMessage(Arrays.asList(toAddresses)); + } + + /** + * Create a message. + * + * @param toAddresses + * @return a message + */ + public Message createMessage(List<String> toAddresses) { + MimeMessage message = new MimeMessage(session); + try { + String fromAddress = settings.getString(Keys.mail.fromAddress, null); + if (StringUtils.isEmpty(fromAddress)) { + fromAddress = "gitblit@gitblit.com"; + } + InternetAddress from = new InternetAddress(fromAddress, "Gitblit"); + message.setFrom(from); + + // determine unique set of addresses + Set<String> uniques = new HashSet<String>(); + for (String address : toAddresses) { + uniques.add(address.toLowerCase()); + } + + Pattern validEmail = Pattern + .compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"); + List<InternetAddress> tos = new ArrayList<InternetAddress>(); + for (String address : uniques) { + if (StringUtils.isEmpty(address)) { + continue; + } + if (validEmail.matcher(address).find()) { + try { + tos.add(new InternetAddress(address)); + } catch (Throwable t) { + } + } + } + message.setRecipients(Message.RecipientType.BCC, + tos.toArray(new InternetAddress[tos.size()])); + message.setSentDate(new Date()); + } catch (Exception e) { + logger.error("Failed to properly create message", e); + } + return message; + } + + /** + * Returns the status of the mail queue. + * + * @return true, if the queue is empty + */ + public boolean hasEmptyQueue() { + return queue.isEmpty(); + } + + /** + * Queue's an email message to be sent. + * + * @param message + * @return true if the message was queued + */ + public boolean queue(Message message) { + if (!isReady()) { + return false; + } + try { + message.saveChanges(); + } catch (Throwable t) { + logger.error("Failed to save changes to message!", t); + } + queue.add(message); + return true; + } + + @Override + public void run() { + if (!queue.isEmpty()) { + if (session != null) { + // send message via mail server + List<Message> failures = new ArrayList<Message>(); + Message message = null; + while ((message = queue.poll()) != null) { + try { + if (settings.getBoolean(Keys.mail.debug, false)) { + logger.info("send: " + StringUtils.trimString(message.getSubject(), 60)); + } + Transport.send(message); + } catch (Throwable e) { + logger.error("Failed to send message", e); + failures.add(message); + } + } + + // push the failures back onto the queue for the next cycle + queue.addAll(failures); + } + } + } + + public void sendNow(Message message) throws Exception { + Transport.send(message); + } +} -- Gitblit v1.9.1