How to create a custom mail servlet for AEM Core Form Container Mail | Community
Skip to main content
Level 2
April 5, 2023
Solved

How to create a custom mail servlet for AEM Core Form Container Mail

  • April 5, 2023
  • 1 reply
  • 1523 views

How do you create a custom mail servlet to be called when using AEM Core Form Container's "Mail" action type?

I need to alter the Out-of-the-Box functionality of the mail action type so that the 'From' field contains placeholder text in the authoring dialog.

I tried copying the mail folder from libs/foundation/components/form/actions/mail and putting it into my app, and added the placeholder property,

but it is not behaving properly since my copied action type folder uses the same jcr property names as the ones in the out-of-the-box mail action type (ex: ./from, ./mailto, etc.)

 

I've tried changing these property names to custom ones so they differ from the OOTB ones, but the day cq mail servlet that handles the mail action type does not recognize my custom attribute names.

 

 

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by lukasz-m

Hi @dms879090,

If you want to use OOTB mechanism for sending email via Core Forms in your custom action, you do not need a custom servlet. You can utilize OOTB one. The main case here, will be to pass values from your custom properties once OOTB mechanism is trying to retrieve original, e.g. if OOTB mechanism is getting value of from prop, it should be mapped to our custom property. This can be easily achieved wrapping original valueMap and control what is returned.

Here is crx structure created using OOTB Mail action:

Here is crx structure created using Custom Mail action:

Here is a sample code that is doing proper mapping:

 

package com.mysite.core.filters; import com.day.cq.commons.ValueMapWrapper; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceWrapper; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; import org.apache.sling.servlets.annotations.SlingServletFilter; import org.apache.sling.servlets.annotations.SlingServletFilterScope; import org.osgi.service.component.annotations.Component; import javax.servlet.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; @Component @SlingServletFilter( scope = { SlingServletFilterScope.COMPONENT}, methods = {"POST"}, selectors = {"form"}, extensions = {"html"}, pattern = "/content/.*" ) public class MailFilter implements Filter { @9944223 public void init(FilterConfig filterConfig) throws ServletException { } @9944223 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) servletRequest; // wrapping should be done only for custom mail action if (isMailAction(slingHttpServletRequest.getResource())) { slingHttpServletRequest = new MailRequestWrapper(slingHttpServletRequest); } filterChain.doFilter(slingHttpServletRequest, servletResponse); } @9944223 public void destroy() { } private boolean isMailAction(Resource resource) { if (resource != null) { ValueMap valueMap = resource.getValueMap(); String actionType = valueMap.get("actionType", String.class); if (actionType != null) { // set value of your custom actionType return actionType.equals("weretail/components/form/actions/mail"); } } return false; } private class MailRequestWrapper extends SlingHttpServletRequestWrapper { public MailRequestWrapper(SlingHttpServletRequest wrappedRequest) { super(wrappedRequest); } @9944223 public Resource getResource() { return new MailResourceWrapper(super.getResource()); } private class MailResourceWrapper extends ResourceWrapper { public MailResourceWrapper(Resource resource) { super(resource); } @9944223 public ValueMap getValueMap() { return new MailValueMapWrapper(super.getValueMap()); } private class MailValueMapWrapper extends ValueMapWrapper { // mapping of OOTB field names with custom ones private Map<String, String> propertiesMapping = new HashMap<String, String>() {{ put("cc", "custom-cc"); put("from", "custom-from"); put("mailto", "custom-mailto"); put("subject", "custom-subject"); }}; public MailValueMapWrapper(ValueMap map) { super(map); } @9944223 public <T> T get(String name, Class<T> type) { return super.get(getNameFromMapping(name), type); } @9944223 public <T> T get(String name, T defaultValue) { return super.get(getNameFromMapping(name), defaultValue); } private String getNameFromMapping(String name) { return propertiesMapping.containsKey(name) ? propertiesMapping.get(name) : name; } } } } }

 

Of course you will need to set actionType that is correlated with your custom mail action implementation, as well as put name of custom fields that corresponds to original ones.

1 reply

lukasz-m
Community Advisor
lukasz-mCommunity AdvisorAccepted solution
Community Advisor
April 7, 2023

Hi @dms879090,

If you want to use OOTB mechanism for sending email via Core Forms in your custom action, you do not need a custom servlet. You can utilize OOTB one. The main case here, will be to pass values from your custom properties once OOTB mechanism is trying to retrieve original, e.g. if OOTB mechanism is getting value of from prop, it should be mapped to our custom property. This can be easily achieved wrapping original valueMap and control what is returned.

Here is crx structure created using OOTB Mail action:

Here is crx structure created using Custom Mail action:

Here is a sample code that is doing proper mapping:

 

package com.mysite.core.filters; import com.day.cq.commons.ValueMapWrapper; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceWrapper; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; import org.apache.sling.servlets.annotations.SlingServletFilter; import org.apache.sling.servlets.annotations.SlingServletFilterScope; import org.osgi.service.component.annotations.Component; import javax.servlet.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; @Component @SlingServletFilter( scope = { SlingServletFilterScope.COMPONENT}, methods = {"POST"}, selectors = {"form"}, extensions = {"html"}, pattern = "/content/.*" ) public class MailFilter implements Filter { @9944223 public void init(FilterConfig filterConfig) throws ServletException { } @9944223 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) servletRequest; // wrapping should be done only for custom mail action if (isMailAction(slingHttpServletRequest.getResource())) { slingHttpServletRequest = new MailRequestWrapper(slingHttpServletRequest); } filterChain.doFilter(slingHttpServletRequest, servletResponse); } @9944223 public void destroy() { } private boolean isMailAction(Resource resource) { if (resource != null) { ValueMap valueMap = resource.getValueMap(); String actionType = valueMap.get("actionType", String.class); if (actionType != null) { // set value of your custom actionType return actionType.equals("weretail/components/form/actions/mail"); } } return false; } private class MailRequestWrapper extends SlingHttpServletRequestWrapper { public MailRequestWrapper(SlingHttpServletRequest wrappedRequest) { super(wrappedRequest); } @9944223 public Resource getResource() { return new MailResourceWrapper(super.getResource()); } private class MailResourceWrapper extends ResourceWrapper { public MailResourceWrapper(Resource resource) { super(resource); } @9944223 public ValueMap getValueMap() { return new MailValueMapWrapper(super.getValueMap()); } private class MailValueMapWrapper extends ValueMapWrapper { // mapping of OOTB field names with custom ones private Map<String, String> propertiesMapping = new HashMap<String, String>() {{ put("cc", "custom-cc"); put("from", "custom-from"); put("mailto", "custom-mailto"); put("subject", "custom-subject"); }}; public MailValueMapWrapper(ValueMap map) { super(map); } @9944223 public <T> T get(String name, Class<T> type) { return super.get(getNameFromMapping(name), type); } @9944223 public <T> T get(String name, T defaultValue) { return super.get(getNameFromMapping(name), defaultValue); } private String getNameFromMapping(String name) { return propertiesMapping.containsKey(name) ? propertiesMapping.get(name) : name; } } } } }

 

Of course you will need to set actionType that is correlated with your custom mail action implementation, as well as put name of custom fields that corresponds to original ones.