A Simple JIRA Webhook for Sending Email Updates

Mike English and I have recently started using Atlassian JIRA to better track the work that the “Professional Problem Solver” (PPS) team handles.

While JIRA is great for managing our tasks and giving us insight into our workload, any external stakeholders without an account do not have the same level of visibility into the work that we are performing. To help with this, I wrote a simple JIRA web hook to update stakeholders via email when a task enters certain states.

The webhook consists of two different components:

  • A JIRA callback
  • A web application

The JIRA callback is set up via the JIRA administration interface, then triggered by specific actions in workflows. When triggered, the callback performs an HTTP POST of JSON data to a particular URI.

The web application runs independently (in this case, on Heroku), and accepts JSON data from the callback. The application parses the data, constructs a message to send out to a user, and then delivers the e-mail.

The JIRA Callback

The JIRA callback is configured in the JIRA administration interface under Settings > System > Advanced > WebHooks. Details about configuring the callbacks can be found in the documentation.

While the callback can be configured to trigger with any change to the issue (edits, new comments, etc.), I wanted to trigger it only when the issue changed to certain states. In this case, I only wanted to notify someone when an issue that they opened entered the “Ready,” “In Progress,” and “Done” states.

I was able to do this by adding an optional post-function to transitions within our JIRA workflow. Our workflow has several transitions, including those for moving an issue into states mentioned above. I configured these transitions to trigger the callback to post JSON data about the issue to my web application.

The Web Application

I wrote a web application in Ruby using Sinatra to accept the JSON from the JIRA callback. The application parses the data, determines what sort of update message to send, creates the message from a template, and then hands it off to an SMTP server for delivery.

The application is quite simple. It’s responsible only for extracting certain details from the JSON blob, then formatting them for easy human readability.

The guts are in the post function below:


  post '/emailupdate' do
    request.body.rewind

    json = JSON.parse(request.body.read)

    logger.debug(json)

    @issue = json['issue']['key']
    @submitter = json['issue']['fields']['customfield_10100']
    @title = json['issue']['fields']['summary']
    @description = json['issue']['fields']['description']
    @old_status = json['transition']['from_status']
    @new_status = json['transition']['to_status']
    @comment = json['comment']

    plain_email = erb :card_update_plain
    html_email = erb :card_update_html

    mail = Mail.new do
      text_part do
        body plain_email
      end

      html_part do
        content_type 'text/html; charset=UTF-8'
        body html_email
      end
    end

    mail.from = 'Support Team <[email protected]>'
    mail.to = "#{@submitter} <#{@submitter}@example.com>"
    mail.subject = "#{@issue} (#{@title}) now has a status of: #{@new_status}"

    mail.delivery_method settings.mail_delivery_method,
                         address: settings.smtp_server,
                         port: settings.smtp_port,
                         domain: settings.smtp_port,
                         user_name: settings.smtp_username,
                         password: settings.smtp_password,
                         authentication: 'plain',
                         enable_starttls_auto: true

    logger.debug(mail.inspect)
    logger.info("Sending mail to: #{mail.to}, with subject: #{mail.subject}")

    begin
      mail.deliver!
    rescue Exception => ex
      logger.error("Something went wrong when sending the e-mail!")
      logger.error(ex)
      halt 500
    end
  end
end

There are two ERB templates: one for plaintext e-mail clients, and one for e-mail clients that support HTML.

Plain text e-mail:

Hi there,

<%= @issue %> (<%= @title %>) has moved from <%= @old_status %> to <%= @new_status %>.

<% unless @comment.blank? %>
* Resolution *
--------------

<%= @comment %>

<% unless @description.blank? %>
* Original Description of Request *
---------------------------------

<%= @description.gsub('---','') %>

<% end %>
<% end %>
---

Please respond to this email if you have any questions.

Best,
- Support Team

(This is an automated status update.)

HTML e-mail:

<div>Hi there,</div>
<br />
<div><b><%= @issue %></b> (<%= @title %>) has moved from <b><%= @old_status %></b> to <b><%= @new_status %></b>.</div>
<% unless @comment.blank? %>
<h2>Resolution</h2>
<div><%= convert_jira_issue_for_email @comment %></div>
<% unless @description.blank? %>
<h2>Original Description of Request</h2>
<div><%= convert_jira_issue_for_email @description %></div>
<% end %>
<% end %>
<hr />
<div>Please respond to this email if you have any questions.<br /><br />Best,<br />- Support Team</div>
<br />
<div><i>(This is an automated status update.)</i></div>

You can find the rest of the web application, along with details for how to set up and run it here. The JIRA webhook model is very flexible and should be easily adapted to simple notification schemes for all sorts of projects.

Conversation
  • Shaun Alexander says:

    Thanks Justin for this great post! I am trying to troubleshoot an error when using this project. I get the HTTP 307 error and was wondering if you had this issue.

  • Comments are closed.