From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 30 Apr 2016 04:19:14 -0400 Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates --- src/main/java/com/gitblit/service/MailService.java | 142 ++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gitblit/service/MailService.java b/src/main/java/com/gitblit/service/MailService.java index 1d5e91f..ec3a84c 100644 --- a/src/main/java/com/gitblit/service/MailService.java +++ b/src/main/java/com/gitblit/service/MailService.java @@ -15,30 +15,36 @@ */ package com.gitblit.service; +import java.io.File; 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.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.regex.Pattern; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; import javax.mail.Authenticator; import javax.mail.Message; +import javax.mail.MessagingException; 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 javax.mail.internet.MimeUtility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.IStoredSettings; import com.gitblit.Keys; +import com.gitblit.models.Mailing; import com.gitblit.utils.StringUtils; /** @@ -63,6 +69,7 @@ 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); + final boolean starttls = settings.getBoolean(Keys.mail.starttls, false); boolean authenticate = !StringUtils.isEmpty(mailUser) && !StringUtils.isEmpty(mailPassword); String server = settings.getString(Keys.mail.server, ""); if (StringUtils.isEmpty(server)) { @@ -81,6 +88,7 @@ props.setProperty("mail.smtp.port", String.valueOf(port)); props.setProperty("mail.smtp.auth", String.valueOf(authenticate)); props.setProperty("mail.smtp.auths", String.valueOf(authenticate)); + props.setProperty("mail.smtp.starttls.enable", String.valueOf(starttls)); if (isGMail || smtps) { props.setProperty("mail.smtp.starttls.enable", "true"); @@ -114,56 +122,112 @@ return session != null; } - /** * Create a message. * - * @param toAddresses + * @param mailing * @return a message */ - public Message createMessage(String... toAddresses) { - return createMessage(Arrays.asList(toAddresses)); - } + public Message createMessage(Mailing mailing) { + if (mailing.subject == null) { + mailing.subject = ""; + } - /** - * Create a message. - * - * @param toAddresses - * @return a message - */ - public Message createMessage(List<String> toAddresses) { - MimeMessage message = new MimeMessage(session); + if (mailing.content == null) { + mailing.content = ""; + } + + Message message = new MailMessageImpl(session, mailing.id); try { String fromAddress = settings.getString(Keys.mail.fromAddress, null); if (StringUtils.isEmpty(fromAddress)) { fromAddress = "gitblit@gitblit.com"; } - InternetAddress from = new InternetAddress(fromAddress, "Gitblit"); + InternetAddress from = new InternetAddress(fromAddress, mailing.from == null ? "Gitblit" : mailing.from); 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) { + + // validate & add TO recipients + List<InternetAddress> to = new ArrayList<InternetAddress>(); + for (String address : mailing.toAddresses) { if (StringUtils.isEmpty(address)) { continue; } if (validEmail.matcher(address).find()) { try { - tos.add(new InternetAddress(address)); + to.add(new InternetAddress(address)); } catch (Throwable t) { } } } - message.setRecipients(Message.RecipientType.BCC, - tos.toArray(new InternetAddress[tos.size()])); + + // validate & add CC recipients + List<InternetAddress> cc = new ArrayList<InternetAddress>(); + for (String address : mailing.ccAddresses) { + if (StringUtils.isEmpty(address)) { + continue; + } + if (validEmail.matcher(address).find()) { + try { + cc.add(new InternetAddress(address)); + } catch (Throwable t) { + } + } + } + + if (settings.getBoolean(Keys.web.showEmailAddresses, true)) { + // full disclosure of recipients + if (to.size() > 0) { + message.setRecipients(Message.RecipientType.TO, + to.toArray(new InternetAddress[to.size()])); + } + if (cc.size() > 0) { + message.setRecipients(Message.RecipientType.CC, + cc.toArray(new InternetAddress[cc.size()])); + } + } else { + // everyone is bcc'd + List<InternetAddress> bcc = new ArrayList<InternetAddress>(); + bcc.addAll(to); + bcc.addAll(cc); + message.setRecipients(Message.RecipientType.BCC, + bcc.toArray(new InternetAddress[bcc.size()])); + } + message.setSentDate(new Date()); + // UTF-8 encode + message.setSubject(MimeUtility.encodeText(mailing.subject, "utf-8", "B")); + + MimeBodyPart messagePart = new MimeBodyPart(); + messagePart.setText(mailing.content, "utf-8"); + //messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); + + if (Mailing.Type.html == mailing.type) { + messagePart.setHeader("Content-Type", "text/html; charset=\"utf-8\""); + } else { + messagePart.setHeader("Content-Type", "text/plain; charset=\"utf-8\""); + } + + MimeMultipart multiPart = new MimeMultipart(); + multiPart.addBodyPart(messagePart); + + // handle attachments + if (mailing.hasAttachments()) { + for (File file : mailing.attachments) { + if (file.exists()) { + MimeBodyPart filePart = new MimeBodyPart(); + FileDataSource fds = new FileDataSource(file); + filePart.setDataHandler(new DataHandler(fds)); + filePart.setFileName(fds.getName()); + multiPart.addBodyPart(filePart); + } + } + } + + message.setContent(multiPart); + } catch (Exception e) { logger.error("Failed to properly create message", e); } @@ -226,4 +290,26 @@ public void sendNow(Message message) throws Exception { Transport.send(message); } + + private static class MailMessageImpl extends MimeMessage { + + final String id; + + MailMessageImpl(Session session, String id) { + super(session); + this.id = id; + } + + @Override + protected void updateMessageID() throws MessagingException { + if (!StringUtils.isEmpty(id)) { + String hostname = "gitblit.com"; + String refid = "<" + id + "@" + hostname + ">"; + String mid = "<" + UUID.randomUUID().toString() + "@" + hostname + ">"; + setHeader("References", refid); + setHeader("In-Reply-To", refid); + setHeader("Message-Id", mid); + } + } + } } -- Gitblit v1.9.1