All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.internet2.middleware.grouper.util.GrouperEmail Maven / Gradle / Ivy

There is a newer version: 5.13.5
Show newest version
/**
 * Copyright 2014 Internet2
 *
 * 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.
 */
/*
 * @author mchyzer
 * $Id: GrouperEmail.java,v 1.1 2008-11-08 03:42:33 mchyzer Exp $
 */
package edu.internet2.middleware.grouper.util;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.Multipart;
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 org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;

import edu.internet2.middleware.grouper.Group;
import edu.internet2.middleware.grouper.GroupFinder;
import edu.internet2.middleware.grouper.GrouperSession;
import edu.internet2.middleware.grouper.Member;
import edu.internet2.middleware.grouper.SubjectFinder;
import edu.internet2.middleware.grouper.cfg.GrouperConfig;
import edu.internet2.middleware.grouper.cfg.dbConfig.ConfigFileName;
import edu.internet2.middleware.grouper.cfg.dbConfig.GrouperConfigHibernate;
import edu.internet2.middleware.grouper.exception.GrouperSessionException;
import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
import edu.internet2.middleware.grouper.misc.GrouperSessionHandler;
import edu.internet2.middleware.grouper.subj.SubjectHelper;
import edu.internet2.middleware.morphString.Morph;
import edu.internet2.middleware.subject.Subject;
import edu.internet2.middleware.subject.provider.SubjectTypeEnum;


/**
 * 

Use this utility to send email from Grouper. Many of these methods are new as of v2.5.47+. The original "set" methods have been there since v1.4+

*

Configured from the smtp external system: * https://spaces.at.internet2.edu/display/Grouper/Grouper+smtp+external+system

*

Unlike most other method chaining classes, you need to call assignRunAsRoot(true) before adding subject and group lookups if you dont want to check security

*

Sample call to send an email: *

*
new GrouperEmail().setTo("[email protected]").setBody("email body").setSubject("email subject").send();
*
*

*

Send an email to a subject: *

*
new GrouperEmail().assignRunAsRoot(true).addSubjectIdentifierToSendTo("mySourceId", "someNetId").setBody("email body").setSubject("email subject").send();
*
*

*

Sample call to send an email: *

*
new GrouperEmail().assignRunAsRoot(true).addGroupToSendTo("a:b:c").setBody("email body").setSubject("email subject").send();
*
*

*

You need to configure email address in your person subject source to send to subjects

*

At least one "to" address is required.

*

To debug emails, set debug to true in the smtp external system, and set the log4j.properties entry: *

*
log4j.logger.edu.internet2.middleware.grouper.util.GrouperEmail = DEBUG
*
*

*/ public class GrouperEmail { /** * attachments */ private List attachments = new ArrayList(); /** * Add a file attachment to the email. * @param attachment * @return the email. */ public GrouperEmail addAttachment(File attachment) { this.attachments.add(attachment); return this; } /** * get the attachments * @return attachemnts */ public List getAttachments() { return attachments; } /** * add an email allowed to the list of allowed emails in config * @param address * @return true if added, false if already there * @since v2.5.48 */ public static boolean addAllowEmailToGroup(String address) { GrouperUtil.assertion(!StringUtils.isBlank(address), "Email address is required!"); GrouperUtil.assertion(groupDereferencePattern.matcher(address).matches(), "Email address must match pattern: groupName@grouper or groupUuid@grouper"); String emailAddressString = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.groupUuidAndNameEmailDereferenceAllow"); Set emailAddressSet = StringUtils.isBlank(emailAddressString) ? new LinkedHashSet() : GrouperUtil.splitTrimToSet(emailAddressString, ","); if (emailAddressSet.contains(address)) { return false; } emailAddressSet.add(address); emailAddressString = GrouperUtil.join(emailAddressSet.iterator(), ","); Set grouperConfigHibernates = GrouperDAOFactory.getFactory().getConfig().findAll(ConfigFileName.GROUPER_PROPERTIES, null, "mail.smtp.groupUuidAndNameEmailDereferenceAllow"); if (GrouperUtil.length(grouperConfigHibernates) == 0) { GrouperConfigHibernate grouperConfigHibernate = new GrouperConfigHibernate(); grouperConfigHibernate.setConfigEncrypted(false); grouperConfigHibernate.setConfigFileHierarchyDb("INSTITUTION"); grouperConfigHibernate.setConfigFileNameDb(ConfigFileName.GROUPER_PROPERTIES.getConfigFileName()); grouperConfigHibernate.setConfigKey("mail.smtp.groupUuidAndNameEmailDereferenceAllow"); grouperConfigHibernate.setValueToSave(emailAddressString); grouperConfigHibernate.saveOrUpdate(true); } else { GrouperUtil.assertion(GrouperUtil.length(grouperConfigHibernates) == 1, "Why is there more than one entry for mail.smtp.groupUuidAndNameEmailDereferenceAllow?"); GrouperConfigHibernate grouperConfigHibernate = grouperConfigHibernates.iterator().next(); grouperConfigHibernate.setValueToSave(emailAddressString); grouperConfigHibernate.saveOrUpdate(false); } return true; } /** * remove an allowed email address from the list of allwoed emails in config * @param address * @return true if removed, false if not there * @since v2.5.48 */ public static boolean removeAllowEmailToGroup(String address) { GrouperUtil.assertion(!StringUtils.isBlank(address), "Email address is required!"); GrouperUtil.assertion(groupDereferencePattern.matcher(address).matches(), "Email address must match pattern: groupName@grouper or groupUuid@grouper"); String emailAddressString = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.groupUuidAndNameEmailDereferenceAllow"); Set emailAddressSet = StringUtils.isBlank(emailAddressString) ? new LinkedHashSet() : GrouperUtil.splitTrimToSet(emailAddressString, ","); if (!emailAddressSet.contains(address)) { return false; } emailAddressSet.remove(address); emailAddressString = GrouperUtil.join(emailAddressSet.iterator(), ","); Set grouperConfigHibernates = GrouperDAOFactory.getFactory().getConfig().findAll(ConfigFileName.GROUPER_PROPERTIES, null, "mail.smtp.groupUuidAndNameEmailDereferenceAllow"); // dont remove since might be in an upstream config file? if (GrouperUtil.length(grouperConfigHibernates) == 0) { GrouperConfigHibernate grouperConfigHibernate = new GrouperConfigHibernate(); grouperConfigHibernate.setConfigEncrypted(false); grouperConfigHibernate.setConfigFileHierarchyDb("INSTITUTION"); grouperConfigHibernate.setConfigFileNameDb(ConfigFileName.GROUPER_PROPERTIES.getConfigFileName()); grouperConfigHibernate.setConfigKey("mail.smtp.groupUuidAndNameEmailDereferenceAllow"); grouperConfigHibernate.setValueToSave(emailAddressString); grouperConfigHibernate.saveOrUpdate(true); } else { GrouperUtil.assertion(GrouperUtil.length(grouperConfigHibernates) == 1, "Why is there more than one entry for mail.smtp.groupUuidAndNameEmailDereferenceAllow?"); GrouperConfigHibernate grouperConfigHibernate = grouperConfigHibernates.iterator().next(); grouperConfigHibernate.setValueToSave(emailAddressString); grouperConfigHibernate.saveOrUpdate(false); } return true; } /** * add a subject (person) to send email to. The email will not send without "to" address(es) * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectToSendTo(Subject subject) { if (subject == null) { return this; } String emailAddress = retrieveEmailAddress(subject); return this.addEmailAddressToSendTo(emailAddress); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "to" address list. The email will not send without "to" address(es) * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdentifierToSendTo(String sourceId, String subjectIdentifier) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdentifierAndSource(subjectIdentifier, sourceId, false); } }); return addSubjectToSendTo(subject); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "to" address list. The email will not send without "to" address(es) * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdToSendTo(String sourceId, String subjectId) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdAndSource(subjectId, sourceId, false); } }); return addSubjectToSendTo(subject); } /** * get an email address for a subject or null if email not found * @param subject to send email to * @return email address */ public static String retrieveEmailAddress(Subject subject) { if (subject != null) { if (!StringUtils.equals(subject.getType().getName(), SubjectTypeEnum.GROUP.getName())) { String emailAttributeName = GrouperEmailUtils.emailAttributeNameForSource(subject.getSourceId()); if (!StringUtils.isBlank(emailAttributeName)) { String emailAddress = subject.getAttributeValue(emailAttributeName); if (!StringUtils.isBlank(emailAddress)) { return emailAddress; } } } } return null; } /** * secure? method that retrieves email addresses from a group * @param group name * @param secure false to run as root * @param exceptionIfNotFound exception if group not found * @return the email addresses found for users in the group */ public static Set retrieveEmailAddresses(final String groupName, boolean secure, boolean exceptionIfNotFound) { Group group = (Group)GrouperSession.internal_callbackRootGrouperSession(!secure, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return GroupFinder.findByName(grouperSession, groupName, exceptionIfNotFound); } }); return retrieveEmailAddresses(group, secure); } /** * secure? method that retrieves email addresses from a group * @param group * @return the email addresses found for users in the group */ public static Set retrieveEmailAddresses(final Group group, boolean secure) { final Set emailAddresses = new TreeSet(); if (group != null) { if (secure && !group.canHavePrivilege(GrouperSession.staticGrouperSession().getSubject(), "readers", false)) { throw new RuntimeException("User '" + SubjectHelper.getPretty(GrouperSession.staticGrouperSession().getSubject()) + "' cannot read: " + group.getName()); } GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { for (Member member : GrouperUtil.nonNull(group.getMembers())) { Subject subject = member.getSubject(); String emailAddress = GrouperEmail.retrieveEmailAddress(subject); if (!StringUtils.isBlank(emailAddress)) { emailAddresses.add(emailAddress); } } return null; } }); } return emailAddresses; } /** * keep list emails (max 100) if testing... */ private static List testingEmails = new ArrayList(); /** * * @return the list of emails */ public static List testingEmails() { return testingEmails; } /** keep count for testing */ public static long testingEmailCount = 0; /** * set the to addresses (comma separated or semicolon separated) */ private String to; /** optional Cc addresses */ private String cc; /** optional Bcc addresses */ private String bcc; /** optional Reply-To addresses */ private String replyTo; /** subject of email */ private String subject; /** email address this is from */ private String from; /** body of email (HTML if the email starts with open HTML bracket <) */ private String body; /** * set the to addresses (comma separated or semicolon separated) * @return to */ public String getTo() { return this.to; } /** * optional comma-separated or semicolon separated list of Cc addresses to send to * @return */ public String getCc() { return this.cc; } /** * optional comma-separated or semicolon separated list of Bcc (blind carbon copy) addresses to send to for all emails * @return */ public String getBcc() { return this.bcc; } /** * optional comma-separated list of addresses for Reply-To header * @return */ public String getReplyTo() { return replyTo; } /** * subject of email * @return subject */ public String getSubject() { return this.subject; } /** * set the from address. generally this will not be set and will come from the config default * @return from */ public String getFrom() { return this.from; } /** * body of email (HTML if the email starts with open HTML bracket <) * @return body */ public String getBody() { return this.body; } /** * */ public GrouperEmail() { //empty } /** * set the to addresses (comma separated or semicolon separated). The email will not send without "to" address(es) * @param theToAddress * @return this for chaining */ public GrouperEmail setTo(String theToAddress) { this.to = theToAddress; return this; } /** * optional comma-separated or semicolon separated list of Cc addresses to send to * @param theCc */ public GrouperEmail setCc(String theCc) { this.cc = theCc; return this; } /** * optional comma-separated or semicolon separated list of Bcc (blind carbon copy) addresses to send to for all emails * @param theBcc */ public GrouperEmail setBcc(String theBcc) { this.bcc = theBcc; return this; } /** * optional comma-separated list of addresses for Reply-To header * @param theReplyTo */ public GrouperEmail setReplyTo(String theReplyTo) { this.replyTo = theReplyTo; return this; } /** * set email subject * @param theSubject * @return this for chaining */ public GrouperEmail setSubject(String theSubject) { this.subject = theSubject; return this; } /** * body of email (HTML if the email starts with open HTML bracket <) * @param theBody * @return this for chaining */ public GrouperEmail setBody(String theBody) { this.body = theBody; return this; } /** * set the from address. generally this will not be set and will come from the config default * @param theFrom * @return the from address */ public GrouperEmail setFrom(String theFrom) { this.from = theFrom; return this; } /** logger */ private static final Log LOG = GrouperUtil.getLog(GrouperEmail.class); /** * try an email * @param args */ public static void main(String[] args) { new GrouperEmail().setBody("hey there").setSubject("my subject").setTo("[email protected]").addAttachment(new File("c:/mchyzer/docs/2110/zoomNonHuman.txt")).send(); } /** * email content type */ private String emailContentType; /** * email content type * @return email content type * @since 2.5.47 */ String getEmailContentType() { return emailContentType; } private boolean mailSent = false; /** * if mail was sent * @return true */ public boolean isMailSent() { return mailSent; } /** * send the email */ public void send() { this.mailSent = false; try { //mail.smtp.server = whatever.school.edu //#mail.from.address = [email protected] String smtpServer = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.server"); if (StringUtils.isBlank(smtpServer)) { throw new RuntimeException("You need to specify the from smtp server mail.smtp.server in grouper.properties"); } String theFrom = StringUtils.defaultIfEmpty(this.from, GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.from.address")); theFrom = StringUtils.defaultIfEmpty(theFrom, GrouperConfig.retrieveConfig().propertyValueString("mail.from.address")); if (!StringUtils.equals("testing", smtpServer) && StringUtils.isBlank(theFrom)) { throw new RuntimeException("You need to specify the from email address mail.smtp.from.address in grouper.properties"); } String subjectPrefix = StringUtils.defaultString(GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.subject.prefix")); if (StringUtils.isBlank(subjectPrefix)) { subjectPrefix = StringUtils.defaultString(GrouperConfig.retrieveConfig().propertyValueString("mail.subject.prefix")); } Properties properties = new Properties(); properties.put("mail.host", smtpServer); String mailTransportProtocol = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.transport.protocol"); if (StringUtils.isBlank(mailTransportProtocol)) { mailTransportProtocol = GrouperConfig.retrieveConfig().propertyValueString("mail.transport.protocol"); } if (StringUtils.isBlank(mailTransportProtocol)) { mailTransportProtocol = "smtp"; } properties.put("mail.transport.protocol", mailTransportProtocol); boolean mailUseProtocolInPropertyNames = true; { String mailUseProtocolInPropertyNamesString = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.use.protocol.in.property.names"); if (StringUtils.isBlank(mailUseProtocolInPropertyNamesString)) { mailUseProtocolInPropertyNamesString = GrouperConfig.retrieveConfig().propertyValueString("mail.use.protocol.in.property.names"); } if (!StringUtils.isBlank(mailUseProtocolInPropertyNamesString)) { mailUseProtocolInPropertyNames = GrouperUtil.booleanValue(mailUseProtocolInPropertyNamesString); } } String propertyProtocol = mailUseProtocolInPropertyNames ? mailTransportProtocol : "smtp"; Authenticator authenticator = null; { final String SMTP_USER = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.user"); String smtpPass = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.pass"); final String SMTP_PASS = StringUtils.isBlank(smtpPass) ? null : Morph.decryptIfFile(smtpPass); if (!StringUtils.isBlank(SMTP_USER)) { properties.setProperty("mail." + propertyProtocol + ".submitter", SMTP_USER); properties.setProperty("mail." + propertyProtocol + ".auth", "true"); authenticator = new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(SMTP_USER, SMTP_PASS); } }; } } boolean useSsl = GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.ssl", false); if (useSsl) { properties.put("mail." + propertyProtocol + ".socketFactory.class", "javax.net.ssl.SSLSocketFactory"); properties.put("mail." + propertyProtocol + ".socketFactory.fallback", "false"); } { String mailSmtpSslProtocols = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.ssl.protocols"); if (!StringUtils.isBlank(mailSmtpSslProtocols)) { properties.put("mail." + propertyProtocol + ".ssl.protocols", mailSmtpSslProtocols); } } { String mailSmtpSocketFactoryClass = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.socketFactory.class"); if (!StringUtils.isBlank(mailSmtpSocketFactoryClass)) { properties.put("mail." + propertyProtocol + ".socketFactory.class", mailSmtpSocketFactoryClass); } } { Boolean mailSmtpSocketFactoryFallback = GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.socketFactory.fallback"); if (mailSmtpSocketFactoryFallback != null) { properties.put("mail." + propertyProtocol + ".socketFactory.fallback", mailSmtpSocketFactoryFallback ? "true" : "false"); } } { Boolean mailSmtpStartTlsEnable = GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.starttls.enable"); if (mailSmtpStartTlsEnable != null) { properties.put("mail." + propertyProtocol + ".starttls.enable", mailSmtpStartTlsEnable ? "true" : "false"); } } { String mailSmtpSslTrust = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.ssl.trust"); if (!StringUtils.isBlank(mailSmtpSslTrust)) { properties.put("mail." + propertyProtocol + ".ssl.trust", mailSmtpSslTrust); } } // setting both mail.smtp.ssl and mail.smtp.starttls.enable probably isn't what the user wants; // the ssl will override, as seen in the java client debug message "STARTTLS requested but already using SSL" if (GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.ssl", false) && GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.starttls.enable", false)) { LOG.warn("Grouper properties mail.smtp.ssl and mail.smtp.starttls.enable are both true; the starttls option will likely not work since the ssl session is established first"); } boolean mailSmtpDebug = false; { String mailSmtpDebugString = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.debug"); if (StringUtils.isBlank(mailSmtpDebugString)) { mailSmtpDebugString = GrouperConfig.retrieveConfig().propertyValueString("mail.debug"); } if (!StringUtils.isBlank(mailSmtpDebugString)) { mailSmtpDebug = GrouperUtil.booleanValue(mailSmtpDebugString); } } if (mailSmtpDebug || LOG.isDebugEnabled()) { properties.put("mail." + propertyProtocol + ".debug", "true"); properties.put("mail.debug", "true"); } //leave blank for default (probably 25), if ssl is true, default is 465, else specify { Integer port = GrouperConfig.retrieveConfig().propertyValueInt("mail.smtp.port"); if (port != null) { properties.put("mail." + propertyProtocol + ".socketFactory.port", port); properties.put("mail." + propertyProtocol + ".port", port); } else { if (useSsl) { properties.put("mail." + propertyProtocol + ".socketFactory.port", "465"); properties.put("mail." + propertyProtocol + ".port", "465"); } } } Session session = Session.getInstance(properties, authenticator); Message message = new MimeMessage(session); String overrideAddresses = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.sendAllMessagesHere"); if (StringUtils.isBlank(overrideAddresses)) { overrideAddresses = GrouperConfig.retrieveConfig().propertyValueString("mail.sendAllMessagesHere"); } boolean sendAllMessagesHereOverride = !StringUtils.equals("testing", smtpServer) && !StringUtils.isBlank(overrideAddresses); StringBuilder sendAllMessagesHereMessage = new StringBuilder(); String theTo = this.to; boolean hasRecipient = false; //GRP-912: mail body is badly quoted-printable encoded => accents issues this.emailContentType = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.grouperEmailContentType"); if (StringUtils.isBlank(this.emailContentType)) { this.emailContentType = GrouperConfig.retrieveConfig().propertyValueString("grouperEmailContentType"); } if (StringUtils.isBlank(this.emailContentType)) { this.emailContentType = "text/plain; charset=utf-8"; } String bodyNewline = "\n"; if (StringUtils.trimToEmpty(this.body).startsWith("<") && !this.emailContentType.toLowerCase().contains("html")) { this.emailContentType = "text/html; charset=utf-8"; } if (StringUtils.trimToEmpty(this.body).startsWith("<") || this.emailContentType.toLowerCase().contains("html")) { bodyNewline = "
"; } if (!StringUtils.isBlank(theTo)) { theTo = StringUtils.replace(theTo, ";", ","); String[] theTos = GrouperUtil.splitTrim(theTo, ","); theTos = dereferenceGroups(theTos); this.to = GrouperUtil.join(theTos, ","); for (String aTo : GrouperUtil.nonNull(theTos, String.class)) { if (!StringUtils.isBlank(aTo) && !StringUtils.equals("null", aTo)) { if (sendAllMessagesHereOverride) { if (hasRecipient) { sendAllMessagesHereMessage.append(", "); } else { sendAllMessagesHereMessage.append("TO: "); } sendAllMessagesHereMessage.append(aTo); } else { message.addRecipient(RecipientType.TO, new InternetAddress(aTo)); } hasRecipient = true; } } if (sendAllMessagesHereOverride) { sendAllMessagesHereMessage.append("" + bodyNewline + ""); // refactor so the email goes here overrideAddresses = StringUtils.replace(overrideAddresses, ";", ","); List overrideAddressesList = new ArrayList<>(); for (String address : GrouperUtil.splitTrim(overrideAddresses, ",")) { if (!StringUtils.isBlank(address)) { overrideAddressesList.add(new InternetAddress(address)); } } message.setRecipients(RecipientType.TO, GrouperUtil.toArray(overrideAddressesList, InternetAddress.class)); } } if (!hasRecipient) { LOG.error("Cant find recipient for email"); return; } // add CC addresses if any if (!StringUtils.isBlank(this.cc)) { String theCc = StringUtils.replace(this.cc, ";", ","); boolean foundCc = false; String[] theCcs = GrouperUtil.splitTrim(theCc, ","); theCcs = dereferenceGroups(theCcs); this.cc = GrouperUtil.join(theCcs, ","); for (String address : GrouperUtil.nonNull(theCcs, String.class)) { if (!StringUtils.isBlank(address)) { if (sendAllMessagesHereOverride) { if (foundCc) { sendAllMessagesHereMessage.append(", "); } else { sendAllMessagesHereMessage.append("CC: "); } sendAllMessagesHereMessage.append(address); foundCc = true; } else { message.addRecipient(RecipientType.CC, new InternetAddress(address)); } } } if (foundCc && sendAllMessagesHereOverride) { sendAllMessagesHereMessage.append("" + bodyNewline + ""); } } // add BCC addresses if any if (!StringUtils.isBlank(this.bcc)) { String theBcc = StringUtils.replace(this.bcc, ";", ","); boolean foundBcc = false; String[] theBccs = GrouperUtil.splitTrim(theBcc, ","); theBccs = dereferenceGroups(theBccs); this.bcc = GrouperUtil.join(theBccs, ","); for (String address : GrouperUtil.nonNull(theBccs, String.class)) { if (!StringUtils.isBlank(address)) { if (sendAllMessagesHereOverride) { if (foundBcc) { sendAllMessagesHereMessage.append(", "); } else { sendAllMessagesHereMessage.append("BCC: "); } sendAllMessagesHereMessage.append(address); foundBcc = true; } else { message.addRecipient(RecipientType.BCC, new InternetAddress(address)); } } } if (foundBcc && sendAllMessagesHereOverride) { sendAllMessagesHereMessage.append("" + bodyNewline + ""); } } // add Reply-To addresses if any if (!StringUtils.isBlank(this.replyTo)) { String theReplyTo = StringUtils.replace(this.replyTo, ";", ","); List replyToList = new ArrayList<>(); for (String address : GrouperUtil.splitTrim(theReplyTo, ",")) { if (!StringUtils.isBlank(address)) { replyToList.add(new InternetAddress(address)); } } if (replyToList.size() > 0) { message.setReplyTo(GrouperUtil.toArray(replyToList, InternetAddress.class)); } } if (!StringUtils.isBlank(theFrom)) { message.addFrom(new InternetAddress[] { new InternetAddress(theFrom) }); } String theSubject = StringUtils.defaultString(subjectPrefix) + this.subject; message.setSubject(theSubject); String emailBody = null; if (sendAllMessagesHereOverride) { sendAllMessagesHereMessage.append("BODY:" + bodyNewline + bodyNewline).append(this.body); emailBody = sendAllMessagesHereMessage.toString(); } else { emailBody = this.body; } // Deal with the attachments. if (GrouperUtil.length(this.attachments) == 0) { message.setContent(emailBody, emailContentType); } else { MimeBodyPart messagePart = new MimeBodyPart(); messagePart.setContent(emailBody, emailContentType); Multipart entireMessage = new MimeMultipart(); entireMessage.addBodyPart(messagePart); MimeBodyPart file = null; for (File attachment : this.attachments) { file = new MimeBodyPart(); file.setDataHandler(new DataHandler(new FileDataSource(attachment.getAbsolutePath()))); file.setFileName(attachment.getName()); entireMessage.addBodyPart(file); } message.setContent(entireMessage); } testingEmailCount++; //if you dont have a server, but want to test, then set this if (!StringUtils.equals("testing", smtpServer)) { if (GrouperConfig.retrieveConfig().propertyValueBoolean("mail.smtp.enabled", true)) { Transport.send(message); this.mailSent = true; } else { LOG.debug("Not sending mail since grouper.properties: mail.smtp.enabled = false"); } } else { StringBuilder logMessage = new StringBuilder("Not sending email since smtp server is 'testing'. "+bodyNewline+"TO: " + this.to + "" + bodyNewline + "FROM: " + theFrom + "" + bodyNewline + "SUBJECT: " + theSubject + "" + bodyNewline + "BODY: " + this.body + "" + bodyNewline + ""); for (File attachment : GrouperUtil.nonNull(this.attachments)) { logMessage.append(", attachment: ").append(attachment.getAbsolutePath()).append(": ").append(FileUtils.byteCountToDisplaySize(attachment.length()) ).append(bodyNewline); } LOG.error(logMessage.toString()); synchronized (GrouperEmail.class) { testingEmails.add(this); while (testingEmails.size() > 100) { testingEmails.remove(0); } } } } catch (RuntimeException e) { throw (RuntimeException)e; } catch (Exception e) { throw new RuntimeException(e); } } /** * groupUuid@grouper or groupName@grouper */ private static Pattern groupDereferencePattern = Pattern.compile("^([^@]+)@grouper$"); /** * * @param theEmails * @return the new list of dereferences emails */ private String[] dereferenceGroups(String[] theEmails) { // # comma separated group name and uuid's to be allow email addresses to dereference. // # for instance: a:b:c@grouper, def345@grouper
// # If a configuration enters in one of those email addresses, and it is in this allow list, then // # dereference the group and member and send email to their individual email addresses. Note that // # groups in this list can have their members discovered so treat their membership as non private. // # using the uuid@grouper gives a little bit of obscurity since the uuid of the group needs to be known // # is it is still security by obscurity which is not true security. There is a max of 100 members it will // # send to // # {valueType: "string", multiple: true} // mail.smtp.groupUuidAndNameEmailDereferenceAllow = String groupUuidAndNameEmailDereferenceAllowString = GrouperConfig.retrieveConfig().propertyValueString("mail.smtp.groupUuidAndNameEmailDereferenceAllow"); if (GrouperUtil.length(theEmails) == 0) { return theEmails; } Set groupUuidAndNameEmailDereferenceAllowSet = null; List theEmailsListResult = new ArrayList(); for (String theEmail : theEmails) { Matcher matcher = groupDereferencePattern.matcher(theEmail); if (matcher.matches()) { String groupIdOrName = matcher.group(1); if (groupUuidAndNameEmailDereferenceAllowSet == null) { groupUuidAndNameEmailDereferenceAllowSet = GrouperUtil.nonNull(GrouperUtil.splitTrimToSet(groupUuidAndNameEmailDereferenceAllowString, ",")); } if (!groupUuidAndNameEmailDereferenceAllowSet.contains(theEmail) && !groupUuidAndNameEmailDereferenceAllowSet.contains(groupIdOrName)) { throw new RuntimeException("grouper.properties mail.smtp.groupUuidAndNameEmailDereferenceAllow does not contain '" + theEmail + "'"); } Set emails = null; if (groupIdOrName.contains(":")) { emails = new TreeSet(retrieveEmailAddresses(groupIdOrName, false, true)); } else { emails = new TreeSet(retrieveEmailAddressesByGroupUuid(groupIdOrName, false, true)); } if (emails.size() > 100) { throw new RuntimeException("Cannot send email to '" + theEmail + "' since size (" + emails.size() + ") is more than 100"); } theEmailsListResult.addAll(emails); } else { theEmailsListResult.add(theEmail); } } return GrouperUtil.toArray(theEmailsListResult, String.class); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "cc" address list * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdentifierToCc(String sourceId, String subjectIdentifier) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdentifierAndSource(subjectIdentifier, sourceId, false); } }); return addSubjectToCc(subject); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "cc" address list * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdToCc(String sourceId, String subjectId) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdAndSource(subjectId, sourceId, false); } }); return addSubjectToCc(subject); } /** * add subject (e.g. person) to cc * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectToCc(Subject subject) { if (subject == null) { return this; } String emailAddress = retrieveEmailAddress(subject); return this.addEmailAddressToCc(emailAddress); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "bcc" address list * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdentifierToBcc(String sourceId, String subjectIdentifier) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdentifierAndSource(subjectIdentifier, sourceId, false); } }); return addSubjectToBcc(subject); } /** * find a subject by sourceId and subjectId, if not found, do nothing. If found, find email address. * If not found, do nothing. If found, add to the "bcc" address list * @param sourceId * @param subjectId * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectIdToBcc(String sourceId, String subjectId) { Subject subject = (Subject)GrouperSession.internal_callbackRootGrouperSession(this.runAsRoot, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { return SubjectFinder.findByIdAndSource(subjectId, sourceId, false); } }); return addSubjectToBcc(subject); } /** * add a group of people to send to. The email will not send without "to" address(es) * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupToSendTo(Group group) { Set emails = retrieveEmailAddresses(group, !this.runAsRoot); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToSendTo(email); } return this; } /** * add a group of people to cc * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupToCc(Group group) { Set emails = retrieveEmailAddresses(group, !this.runAsRoot); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToCc(email); } return this; } /** * set this to true to run as a root session. Note you need to set this before adding subjects and groups to look up */ private boolean runAsRoot; /** * set this to true to run as a root session. Note you need to set this before adding subjects and groups to look up * @param runAsRoot * @return this for chaining * @since 2.5.47 */ public GrouperEmail assignRunAsRoot(boolean runAsRoot) { this.runAsRoot = runAsRoot; return this; } /** * add a group of people to bcc * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupToBcc(Group group) { Set emails = retrieveEmailAddresses(group, !this.runAsRoot); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToBcc(email); } return this; } /** * add email address (if not blank) to send to. The email will not send without "to" address(es) * @param emailAddress * @return this for chaining * @since 2.5.47 */ public GrouperEmail addEmailAddressToSendTo(String emailAddress) { if (StringUtils.isBlank(emailAddress)) { return this; } if (!StringUtils.isBlank(this.to)) { this.to += ","; } else { this.to = ""; } this.to += emailAddress; return this; } /** * add email address (if not blank) to cc * @param emailAddress * @return this for chaining * @since 2.5.47 */ public GrouperEmail addEmailAddressToCc(String emailAddress) { if (StringUtils.isBlank(emailAddress)) { return this; } if (!StringUtils.isBlank(this.cc)) { this.cc += ","; } else { this.cc = ""; } this.cc += emailAddress; return this; } /** * add email address (if not blank) to bcc * @param emailAddress * @return this for chaining * @since 2.5.47 */ public GrouperEmail addEmailAddressToBcc(String emailAddress) { if (StringUtils.isBlank(emailAddress)) { return this; } if (!StringUtils.isBlank(this.bcc)) { this.bcc += ","; } else { this.bcc = ""; } this.bcc += emailAddress; return this; } /** * add a subject (e.g. person) to bcc * @param subject * @return this for chaining * @since 2.5.47 */ public GrouperEmail addSubjectToBcc(Subject subject) { if (subject == null) { return this; } String emailAddress = retrieveEmailAddress(subject); return this.addEmailAddressToBcc(emailAddress); } /** * add a group of people to bcc * @param groupName full system name of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupNameToBcc(String groupName, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddresses(groupName, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToBcc(email); } return this; } /** * add a group of people to cc * @param groupName full system name of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupNameToCc(String groupName, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddresses(groupName, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToCc(email); } return this; } /** * add a group of people to send to * @param groupName full system name of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupNameToSendTo(String groupName, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddresses(groupName, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToSendTo(email); } return this; } /** * add a group of people to bcc * @param groupUuid group uuid of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupUuidToBcc(String groupUuid, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddressesByGroupUuid(groupUuid, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToBcc(email); } return this; } /** * add a group of people to cc * @param groupUuid group uuid of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupUuidToCc(String groupUuid, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddressesByGroupUuid(groupUuid, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToCc(email); } return this; } /** * add a group of people to send to * @param groupUuid group uuid of group * @param exceptionIfNotFound true if exception if group not found * @return this for chaining * @since 2.5.47 */ public GrouperEmail addGroupUuidToSendTo(String groupUuid, boolean exceptionIfNotFound) { Set emails = retrieveEmailAddressesByGroupUuid(groupUuid, !this.runAsRoot, exceptionIfNotFound); for (String email : GrouperUtil.nonNull(emails)) { this.addEmailAddressToSendTo(email); } return this; } /** * secure? method that retrieves email addresses from a group * @param group * @param secure is false if run as root * @param exceptionIfNotFound true if exception if not found * @return the email addresses found for users in the group * @since 2.5.47 */ @SuppressWarnings("unchecked") public static Set retrieveEmailAddressesByGroupUuid(final String groupUuid, boolean secure, boolean exceptionIfNotFound) { return (Set)GrouperSession.internal_callbackRootGrouperSession(!secure, new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { Group group = GroupFinder.findByUuid(grouperSession, groupUuid, exceptionIfNotFound); return (Set)retrieveEmailAddresses(group, secure); } }); } public static List externalSystemTest() { GrouperEmail grouperEmail = new GrouperEmail().assignRunAsRoot(true); String externalSystemTestToType = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToType"); if (StringUtils.equals("emailAddress", externalSystemTestToType)) { String externalSystemTestToAddress = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToAddress"); grouperEmail.addEmailAddressToSendTo(externalSystemTestToAddress); } else if (StringUtils.equals("emailToSubject", externalSystemTestToType)) { String externalSystemTestToSubjectSourceId = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToSubjectSourceId"); String externalSystemTestToSubjectIdType = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToSubjectIdType"); if (StringUtils.equals("subjectId", externalSystemTestToSubjectIdType)) { String externalSystemTestToSubjectId = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToSubjectId"); grouperEmail.addSubjectIdToSendTo(externalSystemTestToSubjectSourceId, externalSystemTestToSubjectId); } else if (StringUtils.equals("subjectIdentifier", externalSystemTestToSubjectIdType)) { String externalSystemTestToSubjectIdentifier = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToSubjectIdentifier"); grouperEmail.addSubjectIdentifierToSendTo(externalSystemTestToSubjectSourceId, externalSystemTestToSubjectIdentifier); } else { throw new RuntimeException("Invalid mail.smtp.externalSystemTestToSubjectIdType: '" + externalSystemTestToSubjectIdType + "'"); } } else if (StringUtils.equals("emailToGroup", externalSystemTestToType)) { String externalSystemTestToGroupIdType = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToGroupIdType"); if (StringUtils.equals("groupUuid", externalSystemTestToGroupIdType)) { String externalSystemTestToGroupId = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToGroupId"); grouperEmail.addGroupUuidToSendTo(externalSystemTestToGroupId, true); } else if (StringUtils.equals("groupName", externalSystemTestToGroupIdType)) { String externalSystemTestToGroupName = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestToGroupName"); grouperEmail.addGroupNameToSendTo(externalSystemTestToGroupName, true); } else { throw new RuntimeException("Invalid mail.smtp.externalSystemTestToGroupIdType: '" + externalSystemTestToGroupIdType + "'"); } } else { throw new RuntimeException("Invalid mail.smtp.externalSystemTestToType: '" + externalSystemTestToType + "'"); } String externalSystemTestSubject = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestSubject"); grouperEmail.setSubject(externalSystemTestSubject); String externalSystemTestBody = GrouperConfig.retrieveConfig().propertyValueStringRequired("mail.smtp.externalSystemTestBody"); grouperEmail.setBody(externalSystemTestBody); String externalSystemTestCcAddress = GrouperConfig.retrieveConfig().propertyValueString("mail.externalSystemTestCcAddress"); if (!StringUtils.isBlank(externalSystemTestCcAddress)) { grouperEmail.setCc(externalSystemTestCcAddress); } String externalSystemTestBccAddress = GrouperConfig.retrieveConfig().propertyValueString("mail.externalSystemTestBccAddress"); if (!StringUtils.isBlank(externalSystemTestBccAddress)) { grouperEmail.setBcc(externalSystemTestBccAddress); } String externalSystemTestFromAddress = GrouperConfig.retrieveConfig().propertyValueString("mail.externalSystemTestFromAddress"); if (!StringUtils.isBlank(externalSystemTestFromAddress)) { grouperEmail.setFrom(externalSystemTestFromAddress); } String externalSystemTestReplyAddresses = GrouperConfig.retrieveConfig().propertyValueString("mail.externalSystemTestReplyAddresses"); if (!StringUtils.isBlank(externalSystemTestReplyAddresses)) { grouperEmail.setReplyTo(externalSystemTestReplyAddresses); } grouperEmail.send(); if (!grouperEmail.isMailSent()) { return GrouperUtil.toList("Mail not sent. Maybe couldnt find recipient, or another reason"); } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy