Custom Email Processing Using Scripts
In Codebeamer, users can add a custom Groovy or Javascript script to process emails arriving at an email address. Using these scripts, they can enable additional actions such as creating new issues, posting comments, and so on.
To configure the emails, create a new email inbox, and at the bottom of page add your Groovy or Javascript script, as shown in the following figure:
The script is executed when e-mails are fetched. This occurs once for every incoming e-mail.
The scope of script contains:
Variable name | Type | Description |
---|
applicationContext | org.springframework.context.ApplicationContext | The Spring context, is used to get access to all DAO 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 | The email processor instance itself. |
logger | org.apache.log4j.Logger | Use this variable to log debug or trace information to log4j. Search the "ScriptEmailProcessor" variable for such logs. |
email | com.intland.codebeamer.inbox.ReceivedMailBean | This bean contains the incoming email text and preprocessed data. Use this to obtain the content of the email. |
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 user who sent the email. This variable is applicable only when the user sends a reply to the notification email from Codebeamer. |
identifiable | IdentifiableDto | When a user sends a reply to a notification email from Codebeamer, then , then this gets the entity, bug or work item from the notification email |
entity | ... | When a user sends a reply to a notification email from Codebeamer, then , then this gets the entity, bug or work item from the notification email |
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. Use this when creating entities, work items, or wiki pages as default owner |
Consider the following when using scrips to configure emails:
• Use the email variable to get access to the email content.
• Use the email.subject to access the subject of incoming email.
• Use the email.getHeader("to") variable to access the "To" field of the email. Similarly, access email headers.
• Emails may contain multiple parts such as multiple HTML and plain text parts. To access such parts, use the following:
◦ email.getPlainTextParts().get(0).getBody() gets the first plaintext part of the email.
◦ email.getHtmlParts().get(0).getBody() gets the first HTML part from the email.
• The email processing runs in the background. There is no user interface component displayed to show the debugging values. Use the logger.info ("...") calls to add the logs or the debug information to the log files on server.
• Email processing happens at specific intervals. You must wait for few minutes until the email is processed. During development, poll the inboxes manually, if required.
• Use calls like trackerItemManager=applicationContext.getBean (TrackerItemManager.class) to access the DAO/Manager classes.
An example of a groovy script which creates a new work item in the related tracker is as follows:
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));
}
}
}
}