You are not logged in. Click here to log in.

codebeamer Application Lifecycle Management (ALM)

Scheduled Maintenance today at 12:00 CET


Search In Project

Search inClear

Tags:  not added yet

Custom email processing using scripts

Starting from codeBeamer 7.8 users can add a custom Groovy or Javascript script to process emails arriving to an email address and do practically anything with that, for example create new issues, comments and whatnot.

To configure just create a new email inbox, and at the bottom of page add your Groovy or Javascript script. This is how it looks on the UI:

The script entered here will be processed regurarly (when emails are polled) and script will be called once for every incoming email.

The scripts' scope will contain:

variable name type description
applicationContext org.springframework.context.ApplicationContext The Spring context, can be used to get access to all DAO's and managers of codeBeamer using applicationContext.getBean("name...") call
scriptWorkflowListener com.intland.codebeamer.inbox.processors.ScriptEmailProcessor The email processor instance itself
scriptEmailProcessor same as scriptWorkflowListener ...
logger org.apache.log4j.Logger Use this logger to log debug/trace infromation to log4j. Look for the logger named "ScriptEmailProcessor" for such logs
email com.intland.codebeamer.inbox.ReceivedMailBean This bean contains the incoming email text and data preprocessed. Use this to get the email's content
inbox com.intland.codebeamer.persistence.dto.InboxDto This bean contains the email inbox definition
emailContext com.intland.codebeamer.inbox.emailresolver.ResolvedEmailContext The bean contains the resolved entity of the reply emails
sender com.intland.codebeamer.persistence.dto.UserDto The sender user of this email, only present if the email is a reply email of an email sent by codeBeamer
identifiable IdentifiableDto When user sends a reply to a notification email from codeBeamer, then this gets the entity/bug/work item the notification email was about
entity ... same as identifiable
bindings javax.script.Bindings The global variable map used by the script engine
user com.intland.codebeamer.persistence.dto.UserDto The default user provided by the inbox. This should be used when creating entities/work items/wiki pages as default owner

Few tips:

  • Use email variable to get access to email's content
  • email.subject contains incoming email's subject
  • email.getHeader("to") is the "to" of the email, access email headers similar to this
  • emails may contain multiple parts: multiple HTML and plain text parts, to access them use:
    • email.getPlainTextParts().get(0).getBody() gets the 1st plaintext part of the email
    • email.getHtmlParts().get(0).getBody() gets the 1st HTML part from the email
  • The email processing is running in background, so has no UI to show debugging values, use the "logger.info("...")" calls to put logs/debug info the the log files on server
  • Email processing only happens periodically, you will have to wait few minutes until email is processed, during development poll the inboxes manually if necessary
  • use calls like trackerItemManager=applicationContext.getBean(TrackerItemManager.class) to access the Dao/Manager classes

An example groovy script which creates new Work items in a tracker is here:


import java.util.regex.*;

import com.intland.codebeamer.persistence.dto.*;
import com.intland.codebeamer.persistence.dto.base.*;
import com.intland.codebeamer.persistence.dao.*;
import com.intland.codebeamer.persistence.util.ArtifactPlusContent;
import com.intland.codebeamer.remoting.ArtifactType;
import com.intland.codebeamer.remoting.DescriptionFormat;
import com.intland.codebeamer.manager.*;
import com.intland.codebeamer.controller.importexport.*;
import org.apache.commons.lang3.*;
import com.intland.codebeamer.text.html.*;
import com.intland.codebeamer.manager.util.*;

logger.info("I'm a groovy script, processing " + email);

// id of Leads tracker on cb.com
leadTrackerId = 94520

trackerDao = applicationContext.getBean(TrackerDao.class);
trackerItemManager = applicationContext.getBean(TrackerItemManager.class);

item = new TrackerItemDto();
leadsTracker = trackerDao.findById(leadTrackerId);
item.setTracker(leadsTracker);

// read custom fields in "Leads" tracker
// using a helper class to access fields by name
fieldAccessor = new com.intland.codebeamer.text.excel.FieldAccessor(applicationContext);
fieldAccessor.setUser(user);

def setField(issue, fieldName, value) {
    field = fieldAccessor.getFieldByName(issue, fieldName);
    if (field != null) {
        field.setValue(issue, value);
    } else {
      logger.warn("Can not find field <" + fieldName +"> on " + issue);
    }
};

def getEmailValue(text, regexp, defaultValue) {
    p = Pattern.compile(regexp);
    matcher = p.matcher(text);
    found = defaultValue;
    if (matcher.find()) {
        found = matcher.group(1);
        found = StringUtils.trimToNull(found);
    }
    logger.info("Found <" + found +"> for regexp <" + regexp +">");

    if (StringUtils.isBlank(found) || "--".equals(found)) {
        found = defaultValue;
    }
    return found;
}

subject = email.subject;
message = "";
if (subject.contains("CB New Account") && (subject.contains("saas.codebeamer.com") || subject.contains("codebeamer.com"))) {
    // a new account is created on saas
    html = email.getHtmlParts().get(0).getBody();
        txt = HtmlCleaner.htmlToText(html);    // convert the HTML to plain text to extract data from there
    logger.info("Cleaned HTML to <" + txt +">")

    firstName = getEmailValue(txt, "(?m)First Name(.*?)$", "--");
    lastName = getEmailValue(txt, "(?m)Last Name(.*?)$", "--");
    email = getEmailValue(txt, "(?m)Email.*?\<mailto:(.*)\>.*?$", "--");
    company = getEmailValue(txt, "(?m)Company(.*)$", email);
        country = getEmailValue(txt, "(?m)Geo-Location(.*?),", "--");

    setField(item, "First name", firstName);
    setField(item, "Last name", lastName);
    setField(item, "E-Mail", email);
    setField(item, "Company", company);
        setField(item, "Country", country);
        setField(item, "Lead Source", "Trial registration");

        desc = subject +"
";
        desc += "Country:" + country +"
";

    item.description = desc;
} else {
    to = email.getHeader("to");
    if ("wordpress@intland.com".equals(to)) {
        txt = email.getPlainTextParts().get(0).getBody();
                logger.info("Processing email text:<"+ txt +">");

        email = getEmailValue(txt, "(?m)Email(.*)$", "--");
        if (! email.equals("--")) {
            firstName = getEmailValue(txt, "(?m)First Name(.*)$", "--");
            lastName = getEmailValue(txt, "(?m)Last Name(.*)$", "--");
            company = getEmailValue(txt, "(?m)Company(.*)$", email);
            phone = getEmailValue(txt, "(?m)Phone(.*)$", "--");
                        country = getEmailValue(txt, "(?m)Geo-Location(.*?),", "--");

            setField(item, "First name", firstName);
            setField(item, "Last name", lastName);
            setField(item, "E-Mail", email);
            setField(item, "Company", company);
            setField(item, "Phone", phone);
                        setField(item, "Country", country);
                        setField(item, "Lead Source", "Trial registration");

                        desc = subject +"
";
                        desc += "Country:" + country +"
";

                        message = getEmailValue(txt, "(?m)(?s)Message:(.*)", "");
                        if (! StringUtils.isBlank(message)) {
                           desc += "
Message:
" + message +"
";
                        }

                     item.description = desc;
        }
    } else {
        item = null;
    }
}

if (item != null) {
    try {
        logger.warn("Creating a new item" + item);
        trackerItemManager.create(user, item, null);
        logger.warn("Created item:" + item);
    } catch (Throwable th) {
        err = th.getMessage();
        logger.info("Failed to create item:" + item, th);

        if (err.contains("same email") || err.contains("already exists")) {
            // if this is a VetoException with "Lead #1234 with same email already exists!" because duplicate emails found
            // and thrown by CodebeamerComTrackerItemListener, then add the subject as comment to the issue
            Pattern issueIdPattern = Pattern.compile("\#(\d*)");
            matcher = issueIdPattern.matcher(err);
            if (matcher.find()) {
                issueId = Integer.valueOf(matcher.group(1));

                logger.warn("Adding comment to issue #" + issueId +", subject:<" + subject +">");
                ArtifactDto comment = new ArtifactDto();
                comment.setOwner(user);
                comment.setDescriptionFormat(DescriptionFormat.WIKI);
                comment.setDescription(subject +"

" + message);
                Date date = new Date();
                comment.setCreatedAt(date);
                comment.setLastModifiedAt(date);
                comment.setTypeId(Integer.valueOf(com.intland.codebeamer.remoting.ArtifactType.ISSUE_ATTACHMENT));
                List<ArtifactPlusContent> arts = Arrays.asList(new ArtifactPlusContent(comment, null));
                trackerItemManager.addAttachments(user, issueId, arts, null, new ActionData(null));
            }
        }
    }
}