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.
Solved! Go to Solution.
Views
Replies
Total Likes
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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
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);
}
@Override
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);
}
@Override
public Resource getResource() {
return new MailResourceWrapper(super.getResource());
}
private class MailResourceWrapper extends ResourceWrapper {
public MailResourceWrapper(Resource resource) {
super(resource);
}
@Override
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);
}
@Override
public <T> T get(String name, Class<T> type) {
return super.get(getNameFromMapping(name), type);
}
@Override
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.
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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
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);
}
@Override
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);
}
@Override
public Resource getResource() {
return new MailResourceWrapper(super.getResource());
}
private class MailResourceWrapper extends ResourceWrapper {
public MailResourceWrapper(Resource resource) {
super(resource);
}
@Override
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);
}
@Override
public <T> T get(String name, Class<T> type) {
return super.get(getNameFromMapping(name), type);
}
@Override
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.