In my current work environment, Jira administration is handled by a separate team. I had created service accounts to be utilized by the Jira mail handler but then realized the mail handler lacks a lot of functionality! What do you mean you can't set component, issueType, or assignee dynamically?
Hm. That would just not do.
I decided to leverage the JIRA API and Amazon's Simple Email Service, along with Lambda.
Let's break it down step by step. First is configuring Amazon's Simple Email Service to receive the email and then consequently write it to S3. Note: the only way (currently) to extract the body of an email utilizing SES is to either write it to Simple Notification Service (SNS) or Simple Storage Service (S3). I have another article that lines out how to create this if you need help.
In Lambda, below is my code. I utilized an amazing Atlassian Python library.
import json, requests, email, boto3, urllib, time, os, base64, re
from JiraPy import *
def handler(event, context):
s3 = boto3.client('s3')
s3r = boto3.resource('s3')
outputBucket = "jira"
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
try:
if not outputBucket:
global outputBucket
outputBucket = bucket
# Use waiter to ensure the file is persisted
waiter = s3.get_waiter('object_exists')
waiter.wait(Bucket=bucket, Key=key)
response = s3r.Bucket(bucket).Object(key)
# Read the raw text file into a Email Object
msg = email.message_from_string(response.get()["Body"].read())
messageTo = msg['To']
messageFrom = msg['From']
messageSubject = msg['Subject']
messageBody = ''
if msg.is_multipart():
for part in msg.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
# skip any text/plain (txt) attachments
if ctype == 'text/plain' and 'attachment' not in cdispo:
messageBody = part.get_payload(decode=True)
break
else:
messageBody = msg.get_payload(decode=True)
if len(msg.get_payload()) == 2:
attachment = msg.get_payload()[1]
else:
data = messageSubject.split('|')
projectKey = data[0]
issueType = data[1]
component = data[2]
summary = data[3]
print(projectKey, issueType, messageFrom, component, summary)
createIssue(projectKey, issueType, messageFrom, component, summary, messageBody)
except Exception as e:
print(e)
raise e
The Jira portion of the script looks like:
def createIssue(projectKey, issueType, assignee, component, summary, messageBody):
if issueType == "Epic":
jira.issue_create(fields={
'project': {'key': projectKey},
'issuetype': {
"name": issueType},
'customfield_10605': summary,
'assignee': {'name': assignee},
'components': [{'name': component}],
'summary': summary,
'description': messageBody,
})
else:
jira.issue_create(fields={
'project': {'key': projectKey},
'issuetype': {
"name": issueType},
'assignee': {'name': assignee},
'components': [{'name': component}],
'summary': summary,
'description': messageBody,
})
def updateIssue(issueKey, messageBody):
jira.issue_add_comment(issueKey, messageBody)
Pretty simple!
Here is a visual representation of what it looks like for the end user.
Curious to hear your thoughts, hopefully this will be useful to someone else in the same predicament.
Top comments (0)