You're viewing help content for version:

Recommended reads 

An adaptive form can have an associated Submit action that triggers when you submit the form. In addition, you can trigger an AEM Workflow on the submitted data.

Consider a scenario where you associate Store Content (deprecated) as the Submit action for an adaptive form. The action creates a node (sling:Folder) that contains the data you submit.

Perform the following steps to trigger an AEM workflow that reads data from the payload you submit. In addition, the workflow fetches your name and email address and sends you an email confirming your data submission.

  1. Create an adaptive form with the required payload (email and user name).

  2. Create a model to define the workflow after you submit the form.

    1. Create workflow components. 

    2. Define the workflow model.

  3. Link the model to an event (in this case, the creation of sling:Folder during form submission).

Creating an adaptive form

Create an XML schema-based Adaptive Form with the fields Enter User Name and Email id for user name and email retrieval, respectively. Click here to download the package with XML Schema-based Adaptive Form.

Creating a workflow model

  1. From the Project home page, go to Tools > Operations > Workflows. Alternatively, directly go to http://:/libs/cq/workflow/content/console.html.

  2. Click New to create a model for your custom workflow.

  3. Click Edit to define your custom workflow.

    Edit the workflow model
  4. Define the workflow for your model that includes various workflow components and handlers. Write a custom Adaptive Form workflow step that sends you an email when you submit the data.

  5. In the CRX repository, create a workflow as depicted. Download the component from here.

    Create a workflow in the CRX repository
  6. Define a process that drafts an email and sends it to your email address. Create an OSGI bundle for this process and deploy it.

    Creating an email workflow
  7. You require processargs to pass the template to your workflow process.

    Creating an OSGI bundle

Workflow process

For details around creating OSGI bundles, see Creating OSGi bundles for the Adobe Digital Marketing Suite using CRXDE.

package com.adobe.aemds.aemworkflow;

import java.util.*;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.mail.Header;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.apache.commons.mail.HtmlEmail;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.w3c.dom.Document;

 * The <code>SendDownloadAssetEmailProcess</code> will send download asset email.
@Component(metatype = false)
        @Property(name = Constants.SERVICE_DESCRIPTION, value = "Send   email notification on submission"),
        @Property(name = "process.label", value = "Send  Email Notification on submission")

public class MailWorkflow implements WorkflowProcess {

    private static final Logger log = LoggerFactory.getLogger(MailWorkflow.class);
    private static final String DEFAULT_CHARSET = "utf-8";

     * resource resolver factory.
    private ResourceResolverFactory resourceResolverFactory;

    @Reference(policy = ReferencePolicy.STATIC)
    private MessageGatewayService messageGatewayService;

    @Reference(policy = ReferencePolicy.STATIC)
    private ResourceResolverFactory resolverFactory;

    public void execute(WorkItem workItem, WorkflowSession session, MetaDataMap metaData)
            throws WorkflowException {
        MetaDataMap workflowMetaDataMap = workItem.getWorkflowData().getMetaDataMap();
        Node submitNode = null;
        ResourceResolver resolver;
        try {
            resolver =
                            (Object) session.getSession()));
        } catch (final Exception e) {
            throw new WorkflowException("could not get resource resolver", e);

        // do not execute upon missing mail service. osgi component still needs to be available for UI
        // selection in workflow step configuration.

        if (messageGatewayService != null) {
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                if (factory != null) {
                    DocumentBuilder builder = factory.newDocumentBuilder();
                    Document doc = null;
                    String payloadPath = workItem.getWorkflowData().getPayload().toString();
                    submitNode = resolver.getResource(payloadPath).adaptTo(Node.class);
                    if (submitNode != null) {
                        InputStream is = submitNode.getProperty("jcr:data").getBinary().getStream();
                        byte[] fileBytes = IOUtils.toByteArray(is);
                        String username = null, emailAdd = null;
                        doc = builder.parse(new ByteArrayInputStream(fileBytes));
                        XPath xPath = XPathFactory.newInstance().newXPath();
                        org.w3c.dom.Node domNode = (org.w3c.dom.Node) xPath.evaluate("//emailid", doc, XPathConstants.NODE);
                        if(domNode !=null) {
                            emailAdd = domNode.getFirstChild().getNodeValue();
                        org.w3c.dom.Node domNodeForName = (org.w3c.dom.Node) xPath.evaluate("//username", doc, XPathConstants.NODE);
                        if(domNodeForName != null) {
                            username = domNodeForName.getFirstChild().getNodeValue();

                        if(emailAdd !=null && username != null ) {
                            ArrayList<InternetAddress> emailRecipients = new ArrayList<InternetAddress>(10);
                            emailRecipients.add(new InternetAddress(emailAdd));
                            if (workflowMetaDataMap != null) {

                                if (emailRecipients != null && emailRecipients.size() != 0) {
                                    String template = getEmailTemplate(metaData, session);
                                    if (template != null) {
                                        // get the string substitutes
                                        Map<String, String> valuesMap = new HashMap<String, String>();
                                        valuesMap.put("event.TimeStamp", Calendar.getInstance().getTime().toString());
                                        valuesMap.put("username", username);
                                        StrSubstitutor substitutor = new StrSubstitutor(valuesMap);

                                        final HtmlEmail email = createEmail(template, substitutor);

                              "Email was sent.");
                                    } else {
                                        log.warn("Did not send email. No email template defined");
                                } else {
                                    log.warn("Did not send email. No recipient addresses or download URL available.");
                            } else {
                                log.warn("Did not send email. No workflow metadata is null.");


            } catch (Exception e) {
                log.error("Fatal error while sending email in workflow", e);
        } else {
            log.warn("cannot send email, mail service unavailable. Please configure Gateway in OSGi Console");

    private String getEmailTemplate(MetaDataMap workflowMetaDataMap, WorkflowSession session) {
        String template = workflowMetaDataMap.get("template", String.class);
        if (template == null) {
            // load mail template
            String templatePath = workflowMetaDataMap.get("templatePath", String.class);
            template = loadTemplate(session.getSession(), templatePath);
        log.debug("Loaded template: {}", template);
        return template;

    private HtmlEmail createEmail(final String template, final StrSubstitutor substitutor) {
        final HtmlEmail email = new HtmlEmail();
        try {
            // Note that substitutions must be called, because they are expected to be
            // US-ASCII only or specially encoded using MimeUtils class, but substitutions might introduce other chars,
            // like e.g. Japanese characters.
            // Further the CountingInputStream class does not seem to properly count when reading Japanese characters.
            final CountingInputStream in = new CountingInputStream(new ByteArrayInputStream(template.getBytes(DEFAULT_CHARSET)));
            final InternetHeaders iHdrs = new InternetHeaders(in);
            final Map<String, String[]> hdrs = new HashMap<String, String[]>();
            final Enumeration e = iHdrs.getAllHeaders();
            while (e.hasMoreElements()) {
                final Header hdr = (Header) e.nextElement();
                final String name = hdr.getName();
                log.debug("Header: {} = {}", name, hdr.getValue());
                hdrs.put(name, iHdrs.getHeader(name));

            // use the counting stream reader to read the mail body
            String templateBody = template.substring(in.getCount());

            // create email

            // set subject
            final String[] ret = hdrs.remove("subject");
            final String subject = (ret == null ? "" : ret[0]);
  "Email subject: " + subject);
            if (!StringUtils.isEmpty(subject)) {

            // set message body
            templateBody = substitutor.replace(templateBody);
            log.debug("Substituted mail body: {}", templateBody);

        } catch (Exception e) {
            log.error("Create email: ", e.getMessage());
        return email;

     * Loads the mail templates from the repository.
     * @param path    mail templates root path
     * @param session session
     * @param charSet The character set
     * @return a reader to the template or <code>null</code> if not valid.
    public String loadTemplate(final Session session, final String path) {
        InputStream is = null;
        try {
            final Node content = session.getNode(path + "/" + JcrConstants.JCR_CONTENT);
            is = content.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
            final InputStreamReader r = new InputStreamReader(is, DEFAULT_CHARSET);
            final StringWriter w = new StringWriter();
            IOUtils.copy(r, w);
            return w.toString();
        } catch (final Exception e) {
            log.error("Error while loading mail template {}:{}", path, e.toString());
        } finally {
        return null;



Implement the WorkflowProcess ( interface.

public void execute(WorkItem workItem, WorkflowSession session, MetaDataMap metaData) throws WorkflowException {  

// implement it


Configure the Email Service for messageGatewayService to not have a null value.

This code relies on the first instance of the email id and the name that appears in the XML file you submit. The data is stored in the jcr:data property of the node that is created based on the data you submit.


Authoring the workflow model


The new component is not yet displayed on the Edit page for the model. Switch to the design mode and enable the component group for the component.

  1. Drag your component. Edit the component, and select an email template. Alternatively, create a template and save the model.

    Editing the email workflow component
  2. Create a small email template.

    Creating an email template
  3. Check the handler for auto transition between steps in the workflow.

Launching the workflow



  1. Trigger the workflow process on a specific event. Navigate to the Workflow user interface, and click the Launcher tab to add a launcher.

  2. Select created as EventType, sling:Folder as NodeType, and /content/user generated/content/forms/af as the path. Select Email on AF Submission as your workflow mode. Also, based on your topology, select the run mode (author, publish, or both).

  3. To test the workflow, open the adaptive form, fill in the details, and click Submit.

    Testing the workflow
  4. To download the workflow package, click the link below.