Email Integration - Solution

 

Overview

The goal of this feature is to develop a mechanism for users to import email into xTuple and have it be automatically associated with appropriate contacts and documents in the database.  The solution should allow users to continue to use their preferred mail clients, but allow them to control what mail they want imported into xTuple.  Once imported, users should also be able to manually associate mail to additional documents such as incidents, orders and quotes.

The strategy to accomplish this will involve two main components.  The first part will be to enhance a new open source email project called Trojita to be used as a tool to import mail into the xTuple database.  Trojita is a lightweight GPL licensed IMAP E-mail client written in C++ with Qt.  Today it can be used to receive, organize and send mail against any standard IMAP server.  Trojita will be enhanced to allow users to select personal IMAP folders to export to a Postgres database.   Because Trojita is working against an IMAP server, users will be able to continue using any mail client of their choice.  The synchronization from Trojita to xTuple will be performed whenever Trojita is launched.  As a second stage development, Trojita will be enhanced so that the synchronization may be run as a service in the background so it will be unnecessary for users to launch the client to export their mail.

The second part of the enhancement will be to enhance xTuple Connect to receive mail exported to it by Trojita.  A series of email tables will be added to Connect to receive the exported mail.  As mail is imported it will be processed by business logic in Connect that associates recognized email addresses with their respective contacts.  Additionally, Connect will scan the subject and body for predefined document reference identifiers and, if any are found, will associate the mail with those documents.  An Email tab will be added to the contacts window and other documents that have contact associations such as Sales Orders, Incident and Opportunities so that users can quickly view email associated with those records.  When the email address is clicked from the contact cluster or widget that launches the users preferred Email client, a document reference will automatically be inserted into the subject line that can later be used as a reference to associate mail imported back into xTuple with that document.  This reference should continue to work as users continue to volley email back and forth from their email client using standard reply mechanisms.

Finally, email sent by Connect itself, such as sales order acknowledgements and incident updates, should insert a record intto the email tables as well.

Functional Requirements

Trojita Client Requirements

  • Add database settings for xTuple (Postgres) login.
  • Allow a user to specify a folder to synchronize the database.
  • Provide a visual cue the folder is selected.
  • Export mail from selected folders to database when mail is refreshed/fetched.
  • A check should exist on the mail identifier to ensure it has not already been imported by another session or client.

Trojita Service Requirements

  • Trojita service daemon automatically starts when user logs into their OS.
  • Automatically connects to IMAP server, fetches mail, and exports to xTuple database per client settings.
  • Changes to client settings immediately affect service.
  • Most work on Windows, Macintosh and Linux as the client does.

xTuple Connect Requirements

  • E-mail repository tables must be added to the xtbatch schema
  • Tables will include triggers to generate associations when mail is inserted
  • Add E-mail tab that displays E-mail associations to the following windows:
    • Contact
    • CRM Account
    • Customer
    • Vendor
    • Employee
    • Opportunity
    • Project
    • Quote
    • Sales Order
    • Transfer Order
    • Purchase Order
    • Return Authorization
    • To Do Item
    • Incident
  • Users will be able to manually associate mail to documents on the E-mail tab.
  • Users will be able to view E-mail detail from the E-mail tab.
  • Users will be able to create new messages or respond to existing messages from the email tab using their local email client.
  • E-Mail sent by either clicking on the contact E-mail address or via the Connect E-mail sender will generate E-mail records and associations.

Related Existing Functionality

The idea of a scripted widget as used in xtConnect for the "edirelation" widget will be used to create an Email Widget that can be re-used in multiple windows.

The convention of viewing a document by saving a copy to a temporary directory then opening as implemented by the documents widget and the Gantt chart in the Time and Expense extension will be used to view mail in a local email client.

The ability to launch an email client using QDesktop services in the contact widget will be used to create email messages pre-populated with text in the users local client. The script toolbox also already has the necessary support to accomplish this.


Conflicting Features

 xTuple Connect already has a rudimentary email interface for sending automated messages such as reports and responses to incidents.  It may be confusing to users that under certain circumstances they will be presented with that window, and under others they will be presented with their native E-mail client

User-Level Functionality

As described above, there are two halves to this development effort.  One side involves modifying the Trojita IMAP client to support mail export to xTuple.  The second half involves modifying xTuple Connect to support the storage and presentation of imported mail. Links to the UI files pictured below are:

settings.ui

emailWidget.ui

emailAttach.ui

WindowChanges

Trojita Window Changes

The Trojita Settings window will include a new tab to specify database connection settings as pictured.  Code required to support Enhanced Authentication and SSL connections may be borrowed from the xTuple client code base.  The port should require a number 1-9999 and the password should use password echo.  A "Test Connection" button should be included to allow users to validate their connection.

The Trojita IMAP client (v.02) is pictured below.  When a valid database has been setup, a new checkable option should exist on right click beneath a separator to "Synchronize to Database."  When a folder has been flagged, a visual queue should be added to the folder icon such as a rightward pointing or circular arrow.

The toolbar buttons will operate as follows:

  • New - Start a new message in the user's e-mail client with the To: address populated with the contact address on the document (if applicable) and an xTuple document reference in the subject.
  • Print - Prints the selected email.
  • Reply - Start a new message in the user's e-mail client with the To:  address populated with the From address on the selected message.  Subject will be pre-pended with RE: and the xTuple document reference if it does not already exist on the subject.  Text from the body of the selected message will be added to the body of the reply message.
  • Reply All - Same as reply except all addresses on the Cc column will be copied to the new message as well.
  • Forward - Same as reply except prepend the subject with FW: and no addresses will be populated.
  • Attach - Open an email attach dialog window that allows users to search messages by contact and associate them to the current document.
  • Detach - Removes the association of the selected message from the document.
There will not be support to include attachments in forwarded messages intiated from xTuple due to security risks posed by the mailto forwarding mechanism to launch and populate the user's email client.  They will, however, be able to achieve this by opening the complete message in their client, and forward the message from there.

Attach Email Dialog

An interactive dialog window will be created to allow users to search for messages by contact to attach to other documents.  The contact widget will allow users to search for the desired contact, while a search box will allow them to further narrow their result set.  The search box will search on address fields, subject and the body fields in the database.  No result set will be returned unless a contact is selected.  The mail result set and corresponding message will be displayed in the same arrangement as the contact widget in a vertical splitter.

The Ok button will only be enabled when a valid message is selected.  When Ok is clicked an association will be made between the document calling the dialog and the selected email.

 

Contact Cluster

Currently when the E-mail address of a contact cluster is clicked, it launches the user's email client with the address of the contact populated in the "To" address.  xTuple Connect should set the subject text to include a document reference as defined in the algorithms section below.

 

Submit EDI

The submit EDI window in xTuple connect should be modified so that the document reference as defined in the algorithms section is included in the subject as defined in the algorithms section below.

 

Report Changes

The only new report definition would be a form used to print selected E-mails.

 

Problems and Alternatives

The initial design calls for the parsing of an inbound message to find associations using a trigger.  This will allow messages to be processed and appear in xTuple in real time.  However, in large installations this could cause a processing drag on the database.  An alternative implementation could have the processing of inbound message associations handled as a batch job, as xTuple Connect is well suited to do.  The table structure and functions will be built in such a way to make implementing this alternative method relatively straight forward.

As mentioned in the conflicts section, users may find it odd that sometimes a message is rendered in their local client, and sometimes using an xTuple interface.  The alternative would be for xTuple to build a complete interface to display all mail messages, and perhaps even send new ones.  This involves building a complex mail rendering mechanism to handle all the presentation nuances of MIME encoded email.  Furthermore it would require substantial rework of the existing xTuple connect  submitEDI window, which is already fairly complex.  The author of Trojita has suggested that we could use his Qt based code as a template for building such an interface, but for now it is beyond the scope of work.  This strategy could be employed as a subsequent round of development if necessary.  On the other hand, users may be perfectly comfortable using their own client in most cases and wish for the application to stay that way.

The attach function will specifically make users search by contact.  There may be calls to be able to search the entire database if the contact is not known, but this would almost certainly over tax the database since email tends to be a high volume data set, and also because full text searching would be involved.  We will start with the contact centric search on this pass, but leave the door open for adding full text search capability in a future release.

Internal Design

Scripting Protocols

The scripts added to xTuple connect should use the following conventions, whether or not they are already used in the current xTuple Connect code:

  • All SQL statements should be stored in and run from the MetaSQL table.
  • A global namespace object should be created for xTuple Connect called xtConnect.
  • To reduce potential conflicts with other packages, all functions should use fully qualified signatures using namespace.window.function as they are implemented in the Time & Expense extension.
    • Example:  xtConnect.emailWidget.reply = function()
  • The emailWidget should be written once, and included in all the various windows it is used.
    • Example: include("emailWidget");

Basic Algorithms

Document reference

The subject of all email correspondence generated from an xTuple document should include a document reference code in the subject line that can be used later by xTuple to associate mail imported back into the database with the appropriate document.  If the necessary reference code already exists in the subject, it should not be re-inserted.

The reference code in the subject will be structured as follows:

[xtref:{type code}-{doc number}]

Example: Quote 10001 -> [xtref:Q-10001]

The type codes will be the same as those used by comments and documents as listed here:

  • T           = Contact
  • CRMA = CRM Account
  • C          = Customer
  • V          = Vendor
  • EMP    = Employee
  • RA      = Return Authorization
  • OPP     = Opportunity
  • J            = Project
  • Q           = Quote
  • S           = Sales Order
  • TO        = Transfer Order
  • P           = Purchase Order
  • TD        = To Do Item
  • INCDT = Incident

 

Contact Cluster and Contact Widget

The contact cluster has a setEmailSubject function accessible to scripting that can be used to add the association when the user clicks on the email address of a contact.  An implementation on Incident, for example, might look something like this:

var xtConnect = new Object;

xtConnect.incident = new Object;

var _cntct = mywindow.findChild("_cntct");

var _number = mywindow.findChild("_number");

xtConnect.incident.numberChanged = function () msg = "[xtref:INCDT-" + _number.text + "]";

_cntct.setEmailSubjectText(msg); _number.textChanged.connect(xtConnect.incident.numberChanged);

Email Widget

The new email widget can use the openUrl() function in the script toolbox to launch the e-mail client with a new message when corresponding buttons are clicked. This toolbox function is an implementation of the openUrl function in the QDesktopServices class which is documented here:

http://doc.trolltech.com/4.6/qdesktopservices.html#openUrl

 

Submit EDI

The code for the submitEDI screen should also be altered to include the reference code in the subject wherever it is used.  The document type is already passed as a variable to this window, and there is an available document number token that can be re-purposed to add in the reference code in the subject.

Email generated by the Submit EDI should be imported into the eml table.  However, this should be accomplished in the xTuple Connect binary after the message has been successfully sent.  Specifically, code would be added to the sendMail function of process.cpp in the xtbatch application to insert a record into the eml table after a successful send.

 

Processing inbound mail

Inbound email should be processed by a series of function calls activated by a trigger on the eml table.  There should be two functions that parse content to make associations in the emlassc table: asscAddress and asscText.  The logic on the trigger would work as follows:

// Process each address field
PERFORM asscAddress(NEW.eml_id, NEW.eml_to);
PERFORM asscAddress(NEW.eml_id, NEW.eml_cc);
PERFORM asscAddress(NEW.eml_id, NEW.eml_bcc);

// Process the contents
PERFORM asscText(NEW.eml_id, NEW.eml_subj);
PERFORM asscText(NEW.eml_id, NEW.eml_body);

// Update the record as processed

NEW.eml_proc = true;

The asscAddress function will parse address out and make associations between contacts with matching addresses.  Postgres string functions can be used for parsing: http://www.postgresql.org/docs/8.2/static/functions-string.html

Count the number of addresses based on the ';' delimter
Loop through the address using split_part to extract each address
Extract the address component from each part
Select contact(s) using the found address
Loop through each contact and insert an emlassc record
Return TRUE if associations made, FALSE if none.

The asscText function looks for an xTuple reference in the text and makes an association

Use the substring function to find a reference match.
If found
  Parse the document type and document number from the substring.
  Select the id for the document based on the number from the appropriate table.
  Insert an emlassoc record for the document.
  Return TRUE
else
  Return FALSE

 

Opening Mail

When a user chooses to open a message from the e-mail widget it will happen using the user's email client using file manipulation and the openUrl functions in the script toolbox as follows:

Get the current email record.
Locate the current temp folder using toolbox.getTempDir();
Create a file path name with the temporary directory + mail unique id + .eml extension.
If the file doesn't already exist, using toolbox.fileExists(string) then
  Use toolboxTextStreamWrite(path, message) to write the contents of the eml_msg field to the new path
Call toolbox.openUrl(string) to open the file.
Use toolbox.removeFile(string) to remove the file.

It is up to the operating system to determine how to open the file. In most cases it should recognize the file as mail message and use their mail client. It may not recognize the file and ask them to select a program to open it with. They should just be able to select their mail client from the applications list and check an option to always use that program for that file type, regardless of the operating system.
 
A working example of several of these file manipulation techniques can be found in the "project" script in the time and expense 2.0.0 package where they are used to implement the Gantt chart.

 

Schema Changes

A set of tables will be created as a repository for email in xTuple and to make the associations between documents. Note the tables will reside in the xTuple Connect schema called xtbatch. The definitions are below:

E-mail Repository Table

CREATE TABLE xtbatch.eml (
  eml_id serial primary key,
  eml_hash text  not null UNIQUE,
  eml_date date not null,
  eml_subj text not null,
  eml_body text not null,
  eml_msg bytea not null,
  eml_status char(1) not null CHECK (eml_status IN ('I','O','C')),

);
 
GRANT ALL ON TABLE xtbatch.eml TO xtrole;
GRANT ALL ON SEQUENCE xtbatch.eml_eml_id_seq TO xtrole;
 
COMMENT ON TABLE xtbatch.eml IS 'E-mail Repository';
COMMENT ON COLUMN xtbatch.eml.eml_id IS 'E-mail primary key';
COMMENT ON COLUMN xtbatch.eml.eml_hash IS 'Email md5 hash of message to check for uniqueness';
COMMENT ON COLUMN xtbatch.eml.eml_subj IS 'E-mail subject';
COMMENT ON COLUMN xtbatch.eml.eml_body IS 'E-mail body text';
COMMENT ON COLUMN xtbatch.eml.eml_msg IS 'Complete e-mail message content;
COMMENT ON COLUMN xtbatch.eml.eml_proc IS 'Processing status I=In-process, O=open,C=complete';
 
Take special note of the uuid used to identify email in the email header.  This will ensure that the same email message can not be imported twice from two different clients.
 

E-Mail Address Table

CREATE TABLE xtbatch.emladdr (
 emladdr_id serial,
 emladdr_eml_id integer not null REFERENCES xtbatch.eml (eml_id),
 emladdr_type text not null CHECK (emladdr_type IN ('FROM','TO','CC','BCC')),
 emladdr_addr text not null,
 emladdr_name text not null,
 )
 
 

GRANT ALL ON TABLE xtbatch.emladdr TO xtrole;
GRANT ALL ON SEQUENCE xtbatch.emladdr_emladdr_id_seq TO xtrole;
 
COMMENT ON TABLE xtbatch.emladdr IS 'E-mail addresses';
COMMENT ON COLUMN xtbatch.emladdr.emladdr_id IS 'E-mail address primary key';
COMMENT ON COLUMN xtbatch.emladdr.emladdr_eml_id IS 'Reference to E-mail primary key';
COMMENT ON COLUMN xtbatch.emladdr.emladdr_type IS 'Address type';
COMMENT ON COLUMN xtbatch.emladdr.emladdr_addr IS 'Address';
COMMENT ON COLUMN xtbatch.emladdr.emladdr_name IS 'Addressee name';
 

E-Mail Association Table

 
CREATE TABLE xtbatch.emlassc (
  emlassc_id serial primary key,
  emlassc_eml_id integer not null references xtbatch.eml (eml_id) ON DELETE CASCADE,
  emlassc_type text not null CHECK (emlassc_type IN ('CRMA','T','C', 'EMP','INCDT','OPP','P','Q','S','TD','TO','V','RA','J')),
  emlassc_assc_id integer );
 
GRANT ALL ON TABLE xtbatch.emlassc TO xtrole;
GRANT ALL ON SEQUENCE xtbatch.emlassc_emlassc_id_seq TO xtrole;
 
COMMENT ON TABLE xtbatch.emlassc IS 'E-mail Associations';
COMMENT ON COLUMN xtbatch.emlassc.emlassc_id IS 'E-mail Association unique identifier';
COMMENT ON COLUMN xtbatch.emlassc.emlassc_eml_id IS 'Reference to E-mail unique identifier';
COMMENT ON COLUMN xtbatch.emlassc.emlassc_type IS 'Association type (i.e. S=Sales Order, C=Customer, T=Contact etc.)';
COMMENT ON COLUMN xtbatch.emlassc.emlassc_assc_id IS 'Reference to associated table key';

 

Release Considerations

This feature should be designed to work on xTuple ERP 3.6.  No core changes should be required to accomodate this feature.

The features relating to mail should be included in a new release xTuple Connect version 3.6.

Trojita will be a separately installed application independent of xTuple using it's own version numbering.  The Trojita development is to be two phased where the first round simply allows the Trojita client to export to the database, and the second will include a service to do the synchronization in the background.  

It may make sense to build an installer for xTuple Connect that can install the Connect executable and/or Trojita.   We can explore installation options as the main development nears completion. 

jrogelstad's picture
Offline
Joined: 12/10/2008
Just an update on where email

Just an update on where email integration is at for those subscribed to this post:

We've been working diligently on this since the end of last year and are getting very close. In fact, we have a working version here that a few guinea pigs (myself included) are trying out. We've found some kinks along the way that we want to get ironed out before we publish a beta, but overall I'm very pleased to actually see a dream that we've talked about for so long actually WORKING!

I'm hopeful we should be able to publish a beta by next week.

John

ned
ned's picture
Offline
Joined: 10/20/2008
Beta now available

The beta of Connect 3.6.0 is now available to customers, and there is also a detailed setup document at http://www.xtuple.org/node/3796.

We'll be doing a private webinar for Feature-Mob participants walking you through the setup on Wednesday, Feb. 2, at 10 am US Eastern time. You can register at https://www1.gotomeeting.com/register/320023512.