HubSpot Ideas

SteveHTM

Workflow filtering of conversations before creating a ticket

I'm just experimenting with the Converstions API and the associated object. My goal was to try and filter incoming emails to determine whether the email was of the right type to generate a ticket.

 

In fact I'm finding this hard to do and want to bring up the issues in hope of a HubSpot team update.

The main issue is the challenge of extracting email content from the conversation. I've developed custom code workflow steps to extract some of the data, but when you return this informatin to the workflow there is nowhere to store the properties!

You can't write to any Conversation object properties or add new properties to support such functionaility like you can do with most other objec types. This seems counter-inuitive for an otherwise powerful worflow feature! Can this limitation be removed? If that were done, then I could use workflows to create tickets of different tyoes according to the conversation/incoming email data 

3 Replies
SteveHTM
Top Contributor | Partner

An update on this challenge - inside a conversations workflow triggered whenenver an email arrives at a given inbox:

- Using a custom code workflow step, I have managed to navigate the conversations data structure ad extract some critical information not made public as standard - such as From email address, To email address, subject and body plus any file attachments (using fileIDs)

- In order to retain this information, extra properties are created in the associated contact record

- Based on the extracted data, I can make a decision on whether a ticket should be created for the incoming email or whether to treat as 'noise'

- Use a flag on the associated contact to trigger a contact workflow for follow up.

- Archive conversations that are regarded as 'noise' to clean up the inbox.

The connected contact workflow then can:

- Create a ticket using the extracted inbound email data on the right pipeline (depending on subject etc.)

- Add an annotated version of the email subject and any attachments to the ticket

- Undertake notifications as required

 

The data and processes to achieve all this should really be made more accessible in the conversations object and workflow options IMHO.

GPrasath
Member

Hi SteveHTM ,

 

We are in the same situation as you. Is it possible to share the custom code? or give some leads on how you managed to extract the date?

 

Thanks

SteveHTM
Top Contributor | Partner

@GPrasath - my process here has been a little pragmatic. Since useful documentation seems to be MIA, I conducted a series of test API calls and deduced the structure of the associated conversation data, including how it references the content of emails. Of course, this dat astructure is totally inconsistent with how emails are represented elsewhere. But, nonetheless, if yout have a sense of the incoming infirmation you can build up a series of options to try and extract what you need.

First step was a conversations type workflow that riggered on a incoming event of type 'email' so that it was possible to extract the threadID and use it in the necessary API call:

  #ThreadID is an input you can find the inthe conversation data structure
  threadID = event["inputFields"]["threadID"]
  base_url="https://api.hubapi.com/conversations/v3/conversations/threads/"
  appToken=os.getenv('appToken')

  #API Request Headers
  headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer ' + appToken,
  }
  request_url = base_url+threadID+'/'+'messages'
  print(request_url)
  
  response = requests.get( request_url, headers=headers)
  print(response.status_code)

  Jresp = response.json()
 

The next step is to detect the data that related to the email itself. This is little fragile due to the data structure variations for different email contents. Hence the try: statements.

  messageIndex=0
  while Jresp["results"][messageIndex]["type"] != "MESSAGE":
    messageIndex+=1
  print("index: ", messageIndex,Jresp["results"][messageIndex]["type"])
  
  email = Jresp["results"][messageIndex]["senders"][0]["deliveryIdentifier"]["value"]
  try:
    name = Jresp["results"][messageIndex]["senders"][0]["name"]
  except:
    name="NoName"
  print(Jresp["results"][messageIndex]["recipients"])
  # Find from field
  toAddr = Jresp["results"][messageIndex]["recipients"][0]["deliveryIdentifier"]["value"]
  timestamp = Jresp["results"][messageIndex]["createdAt"]
  print("Email from: ", name, email, " at: ", timestamp)  
  try:
    title = Jresp["results"][messageIndex]["subject"]
    print("Title: ", type(title), len(title))
  except:
    title="No subject"
  
  fullbody=Jresp["results"][messageIndex]["text"]
  body=fullbody[:800]
  
  try:
    file=Jresp["results"][messageIndex]["attachments"][0]["url"]
    print("URL: ", file)
  except:
    file="Null"
  
  # detect and list potebntially multiple attchments
  try:
    numFiles = len(Jresp["results"][messageIndex]["attachments"])
    fileId=Jresp["results"][messageIndex]["attachments"][0]["fileId"]
    i = 1
    while i < numFiles:
      fileId = fileId + "," + Jresp["results"][messageIndex]["attachments"][i]["fileId"]
      i += 1
  except:
    numFiles = 0
    fileId="0"
  print("Attach count: ",numFiles, fileId)
 

 The real shame here is that you have to store the results in properties of the associated contact rather than the conversation. This includes setting up some kind of trigger for a Contact type workflow to process the information when done.

 

I hope this skeleton is helpful to you and the community. It seems harder than it really should be.

 

Steve