/** * LoklakEmailHandler * Copyright 25.05.2016 by Shiven Mian, @shivenmian * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in the file lgpl21.txt * If not, see <http://www.gnu.org/licenses/>. */ package org.loklak; import java.util.Date; import java.util.Properties; import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import org.eclipse.jetty.util.log.Log; import org.loklak.data.DAO; public class LoklakEmailHandler { public static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; /** * Send an email * @param addressTo Email address to send to * @param subject The email subject * @param text The content * @throws Exception on errors */ public static void sendEmail(@Nonnull String addressTo, @Nonnull String subject, @Nonnull String text) throws Exception { if (!"true".equals(DAO.getConfig("smtp.mails.enabled", "false"))) { throw new Exception("Mail sending disabled"); } String senderEmail = DAO.getConfig("smtp.sender.email", null); String displayname = DAO.getConfig("smtp.sender.displayname", null); String username = DAO.getConfig("smtp.sender.username", null); String password = DAO.getConfig("smtp.sender.password", null); String hostname = DAO.getConfig("smtp.host.name", null); String encryption = DAO.getConfig("smtp.host.encryption", null); int port = DAO.getConfig("smtp.host.port", 0); boolean disableCertChecking = DAO.getConfig("smtp.trustselfsignedcerts", false); if(senderEmail == null || password == null || hostname == null){ throw new Exception("Invalid SMTP configuration"); } Pattern pattern = Pattern.compile(EMAIL_PATTERN); if (!pattern.matcher(addressTo).matches()) { throw new Exception("Invalid email ID"); } if (!pattern.matcher(senderEmail).matches()) { throw new Exception("Invalid sender ID"); } Properties props = createProperties(hostname, port, encryption, disableCertChecking); Session session; if ("none".equals(encryption)) { session = Session.getInstance(props, null); } else { session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); } MimeMessage message = new MimeMessage(session); message.addHeader("Content-type", "text/HTML; charset=UTF-8"); message.addHeader("format", "flowed"); message.addHeader("Content-Transfer-Encoding", "8bit"); message.setSentDate(new Date()); message.setReplyTo(new Address[]{new InternetAddress(senderEmail, displayname)}); message.setFrom(new InternetAddress(senderEmail, displayname)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(addressTo, false)); message.setSubject(subject, "UTF-8"); message.setText(text, "UTF-8"); Transport.send(message); Log.getLog().info("Successfully send mail to " + addressTo); } /** * Check SMTP login credentials * @param hostname the host address * @param username the username/login * @param password the password * @param encryption encryption type (must be none, starttls or tls) * @param port the port number * @param disableCertificateChecking disable certificate checking (behind a ssl-proxy or when the server has a self signed certificate) * @throws MessagingException on error */ public static void checkConnection(@Nonnull String hostname, @Nonnull String username, @Nonnull String password, @Nonnull String encryption, int port, boolean disableCertificateChecking) throws MessagingException{ Properties props = createProperties(hostname, port, encryption, disableCertificateChecking); Session session = Session.getInstance(props, null); Transport transport = session.getTransport("smtp"); transport.connect(username, password); transport.close(); } /** * Shared property creation * @param port the port number * @param encryption encryption type (must be none, starttls or tls) * @param disableCertificateChecking disable certificate checking (behind a ssl-proxy or when the server has a self signed certificate) * @return a Properties object * @throws MessagingException on error */ static private Properties createProperties(@Nonnull String hostname, int port, @Nonnull String encryption, boolean disableCertificateChecking) throws MessagingException{ if(port <= 0 || port > 65535 || !("none".equals(encryption) || "tls".equals(encryption) || "starttls".equals(encryption))){ throw new MessagingException("Invalid Port or Encryption scheme"); } Properties props = new Properties(); props.put("mail.smtp.auth", true); props.put("mail.smtp.port", port); props.put("mail.smtp.host", hostname); if ("starttls".equals(encryption)) { props.put("mail.smtp.starttls.enable", true); } else if ("tls".equals(encryption)) { props.put("mail.smtp.ssl.enable", true); } props.put("mail.smtp.connectiontimeout", 20000); if(disableCertificateChecking){ props.put("mail.smtp.ssl.trust", "*"); } return props; } }