package org.keycloak.email; import org.jboss.logging.Logger; import org.keycloak.connections.truststore.HostnameVerificationPolicy; import org.keycloak.connections.truststore.JSSETruststoreConfigurator; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import javax.mail.Message; 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.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Map; import java.util.Properties; /** * @author Stian Thorgersen */ public class DefaultEmailSenderProvider implements EmailSenderProvider { private static final Logger log = Logger.getLogger(DefaultEmailSenderProvider.class); private final KeycloakSession session; public DefaultEmailSenderProvider(KeycloakSession session) { this.session = session; } @Override public void send(RealmModel realm, UserModel user, String subject, String textBody, String htmlBody) throws EmailException { try { String address = user.getEmail(); Map config = realm.getSmtpConfig(); Properties props = new Properties(); props.setProperty("mail.smtp.host", config.get("host")); boolean auth = "true".equals(config.get("auth")); boolean ssl = "true".equals(config.get("ssl")); boolean starttls = "true".equals(config.get("starttls")); if (config.containsKey("port")) { props.setProperty("mail.smtp.port", config.get("port")); } if (auth) { props.setProperty("mail.smtp.auth", "true"); } if (ssl) { props.setProperty("mail.smtp.ssl.enable", "true"); } if (starttls) { props.setProperty("mail.smtp.starttls.enable", "true"); } if (ssl || starttls) { setupTruststore(props); } props.setProperty("mail.smtp.timeout", "10000"); props.setProperty("mail.smtp.connectiontimeout", "10000"); String from = config.get("from"); Session session = Session.getInstance(props); Multipart multipart = new MimeMultipart("alternative"); if(textBody != null) { MimeBodyPart textPart = new MimeBodyPart(); textPart.setText(textBody, "UTF-8"); multipart.addBodyPart(textPart); } if(htmlBody != null) { MimeBodyPart htmlPart = new MimeBodyPart(); htmlPart.setContent(htmlBody, "text/html; charset=UTF-8"); multipart.addBodyPart(htmlPart); } Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from)); msg.setHeader("To", address); msg.setSubject(subject); msg.setContent(multipart); msg.saveChanges(); msg.setSentDate(new Date()); Transport transport = session.getTransport("smtp"); if (auth) { transport.connect(config.get("user"), config.get("password")); } else { transport.connect(); } transport.sendMessage(msg, new InternetAddress[]{new InternetAddress(address)}); } catch (Exception e) { log.error("Failed to send email", e); throw new EmailException(e); } } private void setupTruststore(Properties props) throws NoSuchAlgorithmException, KeyManagementException { JSSETruststoreConfigurator configurator = new JSSETruststoreConfigurator(session); props.put("mail.smtp.ssl.socketFactory", configurator.getSSLSocketFactory()); if (configurator.getProvider().getPolicy() == HostnameVerificationPolicy.ANY) { props.setProperty("mail.smtp.ssl.trust", "*"); } } @Override public void close() { } }