Lighthouse Email Integration Python Scripts By Joshua Tauberer <http://razor.occams.info> IntroductionIn May 2009 I wrote some Python scripts for my company to provide email integration for our support emails to our new Lighthouse ticketing system. (The Lighthouse folks have a second product called Tender that is a more complete help-desk solution with email integration, but that was too complex for our needs.) lighthouse_imap.py: This script polls an IMAP mail account periodically and creates new tickets or updates existing tickets with the content of the message using the Lighthouse API. It tracks threads using the Message-Id, In-Reply-To, and References email headers, and that's worked out very well for us so far. The script also looks for some simple text commands in the message to change ticket status, assignment, and tags. This is configurable. It also tries to be robust to problems. If there is a connection failure, it tries a few times. If there is an unhandled exception, it will send an email to an address you provide to let you know the script needs to be restarted. Otherwise it just keeps polling indefinitely. It also writes a log file so you can see every action it takes. lighthouse_reminder.py: This script is intended to be run daily (or whatever) and sends an email with the current open tickets. The scripts are posted below. I run them with Python 2.6 (on Ubuntu 9.10). Your mileage may vary with other versions or other platforms. Email me any bugs and I'll try to correct them. The ScriptsDownload
lighthouse.py,
lighthouse_imap.py,
lighthouse_reminder.py,
and lighthouse.conf.sample.
You'll need to rename To run the script on Linux, use If you're using Windows and figure out a good way to start it, send me tips and I'll post them here. Sample ConfigurationHere's
# GENERAL CONFIGURATION.
# Where should the script store its cache (imap.uids) and
# log (lighthouse.log)? Provide the name of a directory.
ScratchPath = "."
# IMAP MAIL CONFIGURATION
ImapSSL = True # True to use IMAPS, False for plain IMAP.
ImapHost = "mail.example.com"
ImapUser = 'yourname'
ImapPassword = 'yourpassword'
PeekDelay = 45 # Seconds between checking the server for new mail.
ImapConnectionAttempts = 10 # Retry attempts before fail.
# LIGHTHOUSE CONFIGURATION
LighthouseHost = "yourapp.lighthouseapp.com"
LighthouseToken = 'abcdefabcdefabcdefabcdef'
LighthouseProject = "/projects/####-appname/"
# ERROR CONFIGURATION
# If the script aborts because of a Python exception, it'll try
# to send an email to this address to let you know you need to
# restart it.
error_notification = "yourname@example.com"
# REMINDERS
# Address to send reminder emails to in lighthouse_reminder.py.
reminder_notification = "team@example.com"
# MESSAGE CONTROL
# A list of email addresses that must be in a To, CC, Resent-To, or Resent-CC
# field in order for a message to be turned into a ticket. Other messages
# are ignored. Addresses must be in all lower case.
must_send_to = ['support@example.com']
# A list of senders who cannot create tickets. It is important to prevent
# automated senders from creating tickets. Especially Lighthouse so we don't
# get any loops. Addresses must be in all lower case.
block_senders = ['support@example.com', 'no-reply@lighthouseapp.com']
# When a sender is a user in the Lighthouse project, they can be
# assigned a ticket automatically if they are the first Lighthouse
# user on the thread. Also we only process special ticket commands if they
# are in emails from a recognized address. This maps email addresses
# to Lighthouse user IDs. You can get user IDs from:
# https://{host}.lighthouseapp.com/projects/{project-id}/memberships.xml
# (but there's no API to get their email addresse).
user_ids = {
"you@example.com": "12345",
}
# Special commands within emails to edit the ticket. This is a
# list of tuples. Each tuple is a command configuration. The
# entries in the tuples are:
#
# 0: Whether the command is restricted to only messages from
# recognized email addresses, as given in user_ids.
# 1: Where to search in the email for the command text. It is
# a header name (e.g. "from"), or else "body" to search
# the message body.
# 2: A string to search for. It is treated as a regular expression
# so parenthesis and square brackets will be treated specially,
# among other characters. Escape them with backslahes if
# necessary.
# 3: What to change in the ticket: status, tag, untag (i.e. remove
# a tag), initialtag (add tag only if this creates a new ticket),
# or assign (set responsible user id).
# 4: The value for the command. For status, this is a new ticket
# status. For tag and untag, a space-spearated list of tags. For
# assign, it is a numeric user ID. If there are parentheses in
# the regular expression, those values are substituted in for
# occurrences of #0, #1, etc. in this value, which is how you
# can create generic tag/untag commands.
ticket_info_patterns = [
# Commands to close, hold, or (re)open a ticket.
(True, "body", "<ticket close>", "status", "resolved"),
(True, "body", "<ticket hold>", "status", "hold"),
(True, "body", "<ticket open>", "status", "open"),
# Regular expression patterns to recognize:
# <tag .....> like <tag bug> etc.
(True, "body", r"<tag\s+([^>]*?)\s*>", "tag", "#0"),
(True, "body", r"<untag\s+([^>]*?)\s*>", "untag", "#0"),
# If the initial email comes from a certain address, give it
# a particular tag.
(False, "to", "support@example.com", "initialtag", "support"),
# Commands to assign the ticket to particular users. Must
# give the numeric user ID of the user. See above to find
# the user IDs of members of a project.
(True, "body", "<assign josh>", "assign", "12345"),
]
|