package com.juick.server; import com.juick.Message; import com.juick.User; import com.juick.service.EmailService; import com.juick.service.MessagesService; import com.juick.service.UserService; import com.juick.service.component.*; import com.juick.util.MessageUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; import javax.inject.Inject; 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 java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import static com.juick.formatters.PlainTextFormatter.formatPost; import static com.juick.formatters.PlainTextFormatter.formatUrl; @Component public class EmailManager implements NotificationListener { public static final String MSGID_PATTERN = "\\.|@|<"; private static final Logger logger = LoggerFactory.getLogger(EmailManager.class); @Inject private EmailService emailService; @Inject private MessagesService messagesService; @Inject private UserService userService; @Override public void processMessageEvent(@Nonnull MessageEvent event) { Message msg = event.getMessage(); List subscribedUsers = event.getUsers(); if (msg.isService()) { return; } if (MessageUtils.isPM(msg)) { String subject = String.format("Private message from %s", msg.getUser().getName()); emailService.getEmails(msg.getTo().getUid(), true).forEach(email -> { emailNotify(email, subject, msg); }); } else if (MessageUtils.isReply(msg)) { Message originalMessage = messagesService.getMessage(msg.getMid()); String subject = String.format("New reply to %s", originalMessage.getUser().getName()); subscribedUsers.stream() .flatMap(user -> emailService.getEmails(user.getUid(), true).stream()) .forEach(email -> emailNotify(email, subject, msg)); } else { String subject = String.format("New message from %s", msg.getUser().getName()); subscribedUsers .forEach(user -> emailService.getEmails(user.getUid(), true) .forEach(email -> emailNotify(email, subject, msg))); } } @Override public void processSubscribeEvent(SubscribeEvent subscribeEvent) { } @Override public void processLikeEvent(LikeEvent likeEvent) { } @Override public void processPingEvent(PingEvent pingEvent) { } @Override public void processMessageReadEvent(MessageReadEvent messageReadEvent) { } private void emailNotify(String email, String subject, Message msg) { Map headers = new HashMap<>(); if (!MessageUtils.isPM(msg)) { headers.put("Message-ID", String.format("<%d.%d@juick.com>", msg.getMid(), msg.getRid())); } if (MessageUtils.isReply(msg)) { if (msg.getReplyto() > 0) { Message replyto = messagesService.getReply(msg.getMid(), msg.getReplyto()); headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", replyto.getMid(), replyto.getRid())); } else { Message original = messagesService.getMessage(msg.getMid()); headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", original.getMid(), original.getRid())); } } String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user," + " discussion, tag or mentioned. Reply to this email directly or view it on Juick: %s.", formatPost(msg), formatUrl(msg)); String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid()); String htmlText = String.format("%s

--
You are receiving this because you are subscribed to this user" + ", discussion, tag or mentioned. Reply to this email directly or view it on Juick." + "
Configure or disable notifications", MessageUtils.formatHtml(msg), formatUrl(msg), msg.getMid(), msg.getRid(), hash, hash); sendEmail(email, subject, plainText, htmlText, headers); } public void sendEmail(String to, String subject, String textPart, String htmlPart, Map messageHeaders) { Properties prop = System.getProperties(); prop.put("mail.smtp.starttls.enable", "true"); Session session = Session.getDefaultInstance(prop); try { Transport transport = session.getTransport("smtp"); MimeMessage message = new MimeMessage(session) { protected void updateMessageID() throws MessagingException { for (Map.Entry entry: messageHeaders.entrySet()) { setHeader(entry.getKey(), entry.getValue()); } } }; message.setFrom(new InternetAddress("juick@juick.com")); message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to)); message.setSubject(subject); MimeBodyPart textBodyPart = new MimeBodyPart(); textBodyPart.setContent(textPart, "text/plain; charset=UTF-8"); Multipart multipart = new MimeMultipart("alternative"); multipart.addBodyPart(textBodyPart); if (StringUtils.isNotBlank(htmlPart)) { MimeBodyPart htmlBodyPart = new MimeBodyPart(); htmlBodyPart.setContent(htmlPart, "text/html; charset=UTF-8"); multipart.addBodyPart(htmlBodyPart); } message.setContent(multipart); User emailUser = userService.getUserByEmail(to); if (!emailUser.isAnonymous()) { message.setHeader("List-Id", "Juick notifications "); message.setHeader("List-Post", ""); message.setHeader("List-Owner", ""); message.setHeader("List-Archive", ""); message.setHeader("List-Unsubscribe", String.format("https://juick.com/settings/unsubscribe?hash=%s", userService.getHashByUID(emailUser.getUid()))); message.setHeader("List-Unsubscribe-Post", "List-Unsubscribe=One-Click"); } message.saveChanges(); transport.connect(); transport.sendMessage(message, message.getAllRecipients()); } catch (MessagingException ex) { logger.error("mail exception", ex); } } }