updated with portal client context and bcc emails
git-svn-id: https://svn.research-infrastructures.eu/d4science/gcube/trunk/portal/portal-manager@133866 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
93fdce97c5
commit
c5c3590919
|
@ -18,9 +18,9 @@
|
|||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="owner.project.facets" value="java"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faceted-project>
|
||||
<installed facet="java" version="1.6"/>
|
||||
<installed facet="jst.utility" version="1.0"/>
|
||||
<installed facet="java" version="1.7"/>
|
||||
</faceted-project>
|
||||
|
|
22
pom.xml
22
pom.xml
|
@ -10,7 +10,7 @@
|
|||
|
||||
<groupId>org.gcube.common.portal</groupId>
|
||||
<artifactId>portal-manager</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<version>2.1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>gCube Portal Manager</name>
|
||||
<description>
|
||||
|
@ -41,14 +41,26 @@
|
|||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.gcube.portal</groupId>
|
||||
<artifactId>client-context-library</artifactId>
|
||||
<version>[1.0.0-SNAPSHOT,)</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.dvos</groupId>
|
||||
<artifactId>usermanagement-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>authorization-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>common-authorization</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -106,8 +118,8 @@
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gcube.common.portal;
|
||||
|
||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -9,17 +11,22 @@ import java.util.Properties;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.gcube.common.authorization.library.provider.UserInfo;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.gcube.portal.clientcontext.client.GCubeClientContext;
|
||||
import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager;
|
||||
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
|
||||
import org.gcube.vomanagement.usermanagement.model.CustomAttributeKeys;
|
||||
import org.gcube.vomanagement.usermanagement.model.Email;
|
||||
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.liferay.portal.kernel.util.StringBundler;
|
||||
import com.liferay.portal.kernel.util.StringPool;
|
||||
import com.liferay.portal.model.Group;
|
||||
import com.liferay.portal.model.VirtualHost;
|
||||
import com.liferay.portal.service.CompanyLocalServiceUtil;
|
||||
import com.liferay.portal.service.LayoutSetLocalServiceUtil;
|
||||
import com.liferay.portal.service.UserLocalServiceUtil;
|
||||
import com.liferay.portal.service.VirtualHostLocalServiceUtil;
|
||||
import com.liferay.portal.util.PortalUtil;
|
||||
|
||||
|
@ -36,6 +43,27 @@ import com.liferay.portal.util.PortalUtil;
|
|||
public class PortalContext {
|
||||
private static final Logger _log = LoggerFactory.getLogger(PortalContext.class);
|
||||
|
||||
/**
|
||||
* Scope separators used in linear syntax.
|
||||
*/
|
||||
protected static final String SCOPE_SEPARATOR = "/";
|
||||
|
||||
private final static String DEFAULT_ROLE = "OrganizationMember";
|
||||
|
||||
private static final String CONFIGURATION_FOLDER = "conf";
|
||||
private static final String INFRA_PROPERTY_FILENAME = "infrastructure.properties";
|
||||
private static final String GCUBE_DEV__CONTEXT_PROPERTY_FILENAME = "gcube-dev-context.properties";
|
||||
|
||||
private static final String DEV_USERNAME_ATTR = "user.username";
|
||||
private static final String DEV_USER_NAME_ATTR = "user.name";
|
||||
private static final String DEV_USER_LASTNAME_ATTR = "user.lastname";
|
||||
private static final String DEV_USER_EMAIL_ATTR = "user.email";
|
||||
|
||||
private static final String DEV_SCOPE_ATTR = "development.scope";
|
||||
private static final String DEV_TOKEN_ATTR = "user.token";
|
||||
|
||||
|
||||
|
||||
private static final String DEFAULT_INFRA_NAME = "gcube";
|
||||
private static final String DEFAULT_VO_NAME = "devsec";
|
||||
private static final String DEFAULT_GATEWAY_NAME = "D4science Gateway";
|
||||
|
@ -60,7 +88,12 @@ public class PortalContext {
|
|||
private void initialize() {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
String propertyfile = getCatalinaHome() + File.separator + "conf" + File.separator + "infrastructure.properties";
|
||||
StringBuilder sb = new StringBuilder(getCatalinaHome());
|
||||
sb.append(File.separator)
|
||||
.append(CONFIGURATION_FOLDER)
|
||||
.append(File.separator)
|
||||
.append(INFRA_PROPERTY_FILENAME);
|
||||
String propertyfile = sb.toString();
|
||||
File propsFile = new File(propertyfile);
|
||||
FileInputStream fis = new FileInputStream(propsFile);
|
||||
props.load( fis);
|
||||
|
@ -72,8 +105,10 @@ public class PortalContext {
|
|||
vos = DEFAULT_VO_NAME;
|
||||
_log.error("infrastructure.properties file not found under $CATALINA_HOME/conf/ dir, setting default infrastructure Name " + infra + " and VO Name " + vos);
|
||||
}
|
||||
|
||||
_log.info("PortalContext configurator correctly initialized on " + infra);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the infrastructure name in which your client runs
|
||||
|
@ -88,6 +123,134 @@ public class PortalContext {
|
|||
public String getVOsAsString() {
|
||||
return this.vos;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param httpServletRequest the httpServletRequest object
|
||||
* @return the instance of the user
|
||||
* @see GCubeUser
|
||||
*/
|
||||
public GCubeUser getCurrentUser(HttpServletRequest httpServletRequest) {
|
||||
String userIdNo = httpServletRequest.getHeader(GCubeClientContext.USER_ID_ATTR_NAME);
|
||||
if (userIdNo != null) {
|
||||
long userId = -1;
|
||||
try {
|
||||
userId = Long.parseLong(userIdNo);
|
||||
return new LiferayUserManager().getUserById(userId);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.error("The userId is not a number -> " + userId);
|
||||
} catch (Exception e) {
|
||||
_log.error("The userId does not belong to any user -> " + userId);
|
||||
}
|
||||
} else {
|
||||
if (isWithinPortal()) {
|
||||
_log.error("It seems your app is running in Liferay but not context was set on this (HttpServletRequest) request, "
|
||||
+ "make sure you have set the gCube ClientContext correctly in your code.");
|
||||
} else {
|
||||
GCubeUser toReturn = readUserFromPropertyFile();
|
||||
_log.debug("getCurrentUser devMode into IDE detected, returning testing user: " + toReturn.toString());
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param httpServletRequest the httpServletRequest object
|
||||
* @return the instance of the user
|
||||
* @see GCubeUser
|
||||
*/
|
||||
public String getCurrentScope(HttpServletRequest httpServletRequest) {
|
||||
String groupIdNo = httpServletRequest.getHeader(GCubeClientContext.VRE_ID_ATTR_NAME);
|
||||
if (groupIdNo != null) {
|
||||
long groupId = -1;
|
||||
try {
|
||||
groupId = Long.parseLong(groupIdNo);
|
||||
LiferayGroupManager gm = new LiferayGroupManager();
|
||||
if (gm.isRootVO(groupId)) {
|
||||
return SCOPE_SEPARATOR + getInfrastructureName();
|
||||
} else
|
||||
return new LiferayGroupManager().getInfrastructureScope(groupId);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.error("The groupId is not a number -> " + groupId);
|
||||
} catch (Exception e) {
|
||||
_log.error("This groupId does not belong to any group in this portal -> " + groupId);
|
||||
}
|
||||
} else {
|
||||
if (isWithinPortal()) {
|
||||
_log.error("It seems your app is running in Liferay but not context was set on this (HttpServletRequest) request, "
|
||||
+ "make sure you have set the gCube ClientContext correctly in your code.");
|
||||
} else {
|
||||
String toReturn = readScopePropertyFile();
|
||||
_log.debug("getCurrentScope devMode into IDE detected, returning scope: " + toReturn.toString());
|
||||
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param httpServletRequest the httpServletRequest object
|
||||
* @return the instance of the user
|
||||
* @see GCubeUser
|
||||
*/
|
||||
public String getCurrentUserToken(HttpServletRequest httpServletRequest) {
|
||||
String groupIdNo = httpServletRequest.getHeader(GCubeClientContext.VRE_ID_ATTR_NAME);
|
||||
if (groupIdNo != null) {
|
||||
String scope = getCurrentScope(httpServletRequest);
|
||||
String username = getCurrentUser(httpServletRequest).getUsername();
|
||||
try {
|
||||
return getAuthorizationToken(username, scope);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error while trying to generate token for user " + username + "in scope " + scope);
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (isWithinPortal()) {
|
||||
_log.error("It seems your app is running in Liferay but not context was set on this (HttpServletRequest) request, "
|
||||
+ "make sure you have set the gCube ClientContext correctly in your code.");
|
||||
} else {
|
||||
String toReturn = readTokenPropertyFile();
|
||||
_log.debug("getCurrentToken devMode into IDE detected, returning scope: " + toReturn.toString());
|
||||
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param username
|
||||
* @param scope
|
||||
* @throws Exception
|
||||
*/
|
||||
private static String getAuthorizationToken(String username, String scope) throws Exception {
|
||||
ScopeProvider.instance.set(scope);
|
||||
_log.debug("calling service token on scope " + scope);
|
||||
List<String> userRoles = new ArrayList<>();
|
||||
userRoles.add(DEFAULT_ROLE);
|
||||
String token = authorizationService().generateUserToken(new UserInfo(username, userRoles), scope);
|
||||
_log.debug("received token: "+token);
|
||||
return token;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return true if you're running into the portal, false if in development
|
||||
*/
|
||||
private boolean isWithinPortal() {
|
||||
try {
|
||||
UserLocalServiceUtil.getService();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_log.trace("Development Mode ON");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the value of the scopes
|
||||
|
@ -159,11 +322,9 @@ public class PortalContext {
|
|||
*
|
||||
* @param request
|
||||
* @return the landing page path of the current Site e.g. "/group/i-marine"
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
*/
|
||||
public String getSiteLandingPagePath(final HttpServletRequest request) {
|
||||
String sitePath = StringPool.BLANK;
|
||||
String sitePath = "";
|
||||
Group site;
|
||||
try {
|
||||
site = getSiteFromServletRequest(request);
|
||||
|
@ -181,11 +342,9 @@ public class PortalContext {
|
|||
*
|
||||
* @param serverName e.g. myportal.mydomain.org
|
||||
* @return the landing page path of the current Site e.g. "/group/i-marine"
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
*/
|
||||
public String getSiteLandingPagePath(final String serverName) {
|
||||
String sitePath = StringPool.BLANK;
|
||||
String sitePath = "";
|
||||
Group site;
|
||||
try {
|
||||
site = getSiteFromServerName(serverName);
|
||||
|
@ -203,8 +362,6 @@ public class PortalContext {
|
|||
*
|
||||
* @param request
|
||||
* @return the current Group instance based on the request
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
*/
|
||||
private Group getSiteFromServletRequest(final HttpServletRequest request) throws Exception {
|
||||
String serverName = request.getServerName();
|
||||
|
@ -225,9 +382,7 @@ public class PortalContext {
|
|||
/**
|
||||
*
|
||||
* @param serverName e.g. myportal.mydomain.org
|
||||
* @return
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
* @return the Liferay Group instance responding to the servename passed as parameter
|
||||
*/
|
||||
private Group getSiteFromServerName(final String serverName) throws Exception {
|
||||
_log.debug("serverName passed is " + serverName);
|
||||
|
@ -252,28 +407,10 @@ public class PortalContext {
|
|||
* @param isPrivate
|
||||
* @param isUser
|
||||
* @return
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
*/
|
||||
@Deprecated
|
||||
private static String getGroupFriendlyURL(HttpServletRequest request, final Group currentGroup) throws Exception {
|
||||
String friendlyURL = GCubePortalConstants.PREFIX_GROUP_URL;
|
||||
StringBundler sb = new StringBundler();
|
||||
sb.append(friendlyURL).append(currentGroup.getFriendlyURL());
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
* @param request
|
||||
* @param currentGroup
|
||||
* @param isPrivate
|
||||
* @param isUser
|
||||
* @return
|
||||
* @throws PortalException
|
||||
* @throws SystemException
|
||||
*/
|
||||
private static String getGroupFriendlyURL(final Group currentGroup) throws Exception {
|
||||
String friendlyURL = GCubePortalConstants.PREFIX_GROUP_URL;
|
||||
StringBundler sb = new StringBundler();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(friendlyURL).append(currentGroup.getFriendlyURL());
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -397,29 +534,88 @@ public class PortalContext {
|
|||
return toReturn;
|
||||
}
|
||||
/**
|
||||
* use org.gcube.vomanagement.usermanagement.impl.LiferayUserManager#getAdmin method
|
||||
* for development purposes only
|
||||
*/
|
||||
@Deprecated
|
||||
public String getAdministratorUsername() {
|
||||
//get the portles to look for from the property file
|
||||
private static GCubeUser readUserFromPropertyFile() {
|
||||
Properties props = new Properties();
|
||||
String toReturn = "";
|
||||
|
||||
try {
|
||||
String propertyfile = getCatalinaHome() + File.separator + "conf" + File.separator + "gcube-data.properties";
|
||||
StringBuilder sb = new StringBuilder(getCatalinaHome());
|
||||
sb.append(File.separator)
|
||||
.append(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME);
|
||||
String propertyfile = sb.toString();
|
||||
File propsFile = new File(propertyfile);
|
||||
FileInputStream fis = new FileInputStream(propsFile);
|
||||
props.load( fis);
|
||||
toReturn = props.getProperty(GCubePortalConstants.ADMIN_USERNAME);
|
||||
long userId = -1;
|
||||
String username = props.getProperty(DEV_USERNAME_ATTR);
|
||||
String email = props.getProperty(DEV_USER_EMAIL_ATTR);
|
||||
String firstName = props.getProperty(DEV_USER_NAME_ATTR);
|
||||
String middleName = "";
|
||||
String lastName = props.getProperty(DEV_USER_LASTNAME_ATTR);
|
||||
String fullname = firstName + lastName;
|
||||
long registrationDate = -1;
|
||||
String userAvatarId = "-1";
|
||||
boolean male = true;
|
||||
String jobTitle = "TestingAccount";
|
||||
List<Email> emailAddresses = new ArrayList<>();
|
||||
|
||||
return new GCubeUser(userId, username, email, firstName, middleName, lastName, fullname, registrationDate, userAvatarId, male, jobTitle, emailAddresses);
|
||||
}
|
||||
//catch exception in case properties file does not exist
|
||||
catch(IOException e) {
|
||||
toReturn = "massimiliano.assante";
|
||||
_log.error("gcube-data.properties file not found under $CATALINA_HOME/conf dir, returning default administrator" + toReturn);
|
||||
return toReturn;
|
||||
_log.error(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME + " file not found under $CATALINA_HOME dir");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* for development purposes only
|
||||
*/
|
||||
private static String readTokenPropertyFile() {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder(getCatalinaHome());
|
||||
sb.append(File.separator)
|
||||
.append(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME);
|
||||
String propertyfile = sb.toString();
|
||||
File propsFile = new File(propertyfile);
|
||||
FileInputStream fis = new FileInputStream(propsFile);
|
||||
props.load( fis);
|
||||
String token = props.getProperty(DEV_TOKEN_ATTR);
|
||||
if (token != null && token.compareTo("") != 0)
|
||||
return token;
|
||||
else {
|
||||
_log.error("Token property "+ DEV_TOKEN_ATTR + " is missing or empty in the property file " + propertyfile);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
_log.error(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME + " file not found under $CATALINA_HOME dir");
|
||||
return null;
|
||||
}
|
||||
}/**
|
||||
* for development purposes only
|
||||
*/
|
||||
private static String readScopePropertyFile() {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder(getCatalinaHome());
|
||||
sb.append(File.separator)
|
||||
.append(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME);
|
||||
String propertyfile = sb.toString();
|
||||
File propsFile = new File(propertyfile);
|
||||
FileInputStream fis = new FileInputStream(propsFile);
|
||||
props.load( fis);
|
||||
String scope = props.getProperty(DEV_SCOPE_ATTR);
|
||||
if (scope.startsWith(SCOPE_SEPARATOR))
|
||||
return scope;
|
||||
else {
|
||||
_log.error("Scope is not valid, does not start with " + SCOPE_SEPARATOR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
_log.error(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME + " file not found under $CATALINA_HOME dir");
|
||||
return null;
|
||||
}
|
||||
_log.debug("Returning Administrator username: " + toReturn );
|
||||
return toReturn;
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -31,6 +31,7 @@ public class EmailNotification {
|
|||
private String emailrecipients[];
|
||||
|
||||
private List<InternetAddress> emailRecipientsInCC;
|
||||
private List<InternetAddress> emailRecipientsInBCC;
|
||||
/**
|
||||
* Email's subject
|
||||
*/
|
||||
|
@ -100,6 +101,14 @@ public class EmailNotification {
|
|||
}
|
||||
}
|
||||
|
||||
public void addRecipientInBCC(String email) {
|
||||
try {
|
||||
emailRecipientsInBCC.add(new InternetAddress(email));
|
||||
} catch (AddressException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendEmail() {
|
||||
Properties props = System.getProperties();
|
||||
props.put("mail.smtp.host", MAIL_SERVICE_HOST);
|
||||
|
@ -131,7 +140,10 @@ public class EmailNotification {
|
|||
for (InternetAddress email : emailRecipientsInCC) {
|
||||
mimeMessage.addRecipient(Message.RecipientType.CC, email);
|
||||
}
|
||||
|
||||
// EMAIL BCC Recipients
|
||||
for (InternetAddress email : emailRecipientsInBCC) {
|
||||
mimeMessage.addRecipient(Message.RecipientType.BCC, email);
|
||||
}
|
||||
mimeMessage.setSubject(emailSubject);
|
||||
mimeMessage.setContent(emailBody.toString(), "text/html; charset=UTF-8");
|
||||
mimeMessage.setSentDate(new Date());
|
||||
|
|
Loading…
Reference in New Issue